gdharness 1.3.42 → 1.3.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/build/cli.js +62 -9
  2. package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
  3. package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
  4. package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
  5. package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
  6. package/build/godot/addons/gdharness_editor/file_reads.gd +83 -42
  7. package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
  8. package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
  9. package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
  10. package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
  11. package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
  12. package/build/godot/addons/gdharness_editor/reading.gd +37 -12
  13. package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
  14. package/build/godot/addons/gdharness_editor/scene_file.gd +109 -79
  15. package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
  16. package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
  17. package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
  18. package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
  19. package/build/godot/addons/gdharness_editor/tools/animation_states.gd +37 -27
  20. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
  21. package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
  22. package/build/godot/addons/gdharness_editor/tools/class_tools.gd +34 -30
  23. package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
  24. package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
  25. package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
  26. package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
  27. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +166 -107
  28. package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
  29. package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
  30. package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
  31. package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
  32. package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +12 -5
  33. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
  34. package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
  35. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
  36. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
  37. package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
  38. package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
  39. package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
  40. package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
  41. package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
  42. package/build/godot/addons/gdharness_runtime/reading.gd +37 -12
  43. package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
  44. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
  45. package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
  46. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
  47. package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
  48. package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
  49. package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
  50. package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
  51. package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
  52. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +34 -17
  53. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
  54. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
  55. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
  56. package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
  57. package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
  58. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
  59. package/build/godot/addons/gdharness_runtime/runtime_touch.gd +15 -15
  60. package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
  61. package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
  62. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
  63. package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
  64. package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
  65. package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
  66. package/build/godot/addons/gdharness_tests/bench.gd +4 -5
  67. package/build/godot/addons/gdharness_tests/event.gd +10 -5
  68. package/build/godot/addons/gdharness_tests/share.gd +38 -18
  69. package/build/godot/addons/gdharness_tests/suites.gd +3 -3
  70. package/build/godot/addons/gdharness_tests/wait.gd +3 -2
  71. package/build/godot/loader/loader.gd +9 -9
  72. package/build/godot/operations/animation_reads.gd +55 -33
  73. package/build/godot/operations/audio_buses.gd +48 -19
  74. package/build/godot/operations/class_cache.gd +16 -11
  75. package/build/godot/operations/classdb_queries.gd +89 -44
  76. package/build/godot/operations/declared_values.gd +68 -32
  77. package/build/godot/operations/dependencies.gd +139 -93
  78. package/build/godot/operations/editor_tools.gd +9 -10
  79. package/build/godot/operations/export_presets.gd +100 -54
  80. package/build/godot/operations/file_reads.gd +83 -42
  81. package/build/godot/operations/file_walk.gd +12 -5
  82. package/build/godot/operations/gdscript_analysis.gd +86 -65
  83. package/build/godot/operations/gdscript_authoring.gd +83 -36
  84. package/build/godot/operations/godot_operations.gd +17 -11
  85. package/build/godot/operations/import_pipeline.gd +110 -59
  86. package/build/godot/operations/input_actions.gd +62 -39
  87. package/build/godot/operations/patterns.gd +3 -1
  88. package/build/godot/operations/plugins.gd +36 -16
  89. package/build/godot/operations/project_config.gd +53 -29
  90. package/build/godot/operations/project_diagnostics.gd +24 -11
  91. package/build/godot/operations/project_file.gd +16 -16
  92. package/build/godot/operations/project_validation.gd +71 -44
  93. package/build/godot/operations/property_paths.gd +22 -12
  94. package/build/godot/operations/property_values.gd +143 -78
  95. package/build/godot/operations/reading.gd +37 -12
  96. package/build/godot/operations/rename_checks.gd +2 -2
  97. package/build/godot/operations/resource_files.gd +11 -9
  98. package/build/godot/operations/same_values.gd +4 -4
  99. package/build/godot/operations/scene_connections.gd +27 -13
  100. package/build/godot/operations/script_check.gd +52 -49
  101. package/build/godot/operations/serialisation.gd +75 -51
  102. package/build/godot/operations/setting_reads.gd +7 -6
  103. package/build/godot/operations/value_shapes.gd +5 -6
  104. package/build/godot/tests/listed.gd +321 -268
  105. package/package.json +1 -1
@@ -1,11 +1,9 @@
1
1
  @tool
2
2
  extends RefCounted
3
-
4
3
  ## What a property declares beyond its type: the values of its enum and the range it is exported
5
4
  ## with, for taking a value by name and for saying when a value written lies outside them.
6
5
 
7
6
  const GdhRead = preload("reading.gd")
8
-
9
7
  ## The section of layer_names in project.godot naming the layers of each layers hint.
10
8
  const LAYER_NAMES: Dictionary[int, String] = {
11
9
  PROPERTY_HINT_LAYERS_2D_PHYSICS: "2d_physics",
@@ -27,7 +25,7 @@ static func layers_in(hint: int, mask: int) -> Array[Dictionary]:
27
25
  for layer: int in range(1, MASK_LAYERS + 1):
28
26
  if mask & (1 << (layer - 1)) == 0:
29
27
  continue
30
- var entry: Dictionary = {"layer": layer}
28
+ var entry: Dictionary = { "layer": layer }
31
29
  var name: String = str(
32
30
  ProjectSettings.get_setting("layer_names/%s/layer_%d" % [LAYER_NAMES[hint], layer], "")
33
31
  )
@@ -119,10 +117,12 @@ static func engine_constants(target: Object, property: String) -> Dictionary:
119
117
  ## names by it, as [true, number], or [false, why] naming the values, with [param holder] naming the
120
118
  ## target in the refusal. [false, ""] for a word that is a number, which converts as one.
121
119
  ##
122
- ## An enum is written by the name of a value as well as its number, since the name is what the script
123
- ## and the inspector show and the number is only where the value happens to sit. Tried as the script
124
- ## spells it, then as the hint does, then as the engine's constant.
125
- static func enum_by_name(target: Object, declared: Dictionary, word: String, holder: String) -> Array:
120
+ ## An enum is written by the name of a value as well as its number, since the name is what the
121
+ ## script and the inspector show and the number is only where the value happens to sit. Tried as the
122
+ ## script spells it, then as the hint does, then as the engine's constant.
123
+ static func enum_by_name(
124
+ target: Object, declared: Dictionary, word: String, holder: String
125
+ ) -> Array:
126
126
  var property: String = str(declared.get("name", ""))
127
127
  var choices: Dictionary = enum_of(target, declared)
128
128
  var chosen: Variant = enum_named(choices, word)
@@ -144,7 +144,9 @@ static func enum_refusal(
144
144
  ) -> String:
145
145
  var ways: String = "by name or by number"
146
146
  if not constants.is_empty():
147
- ways = "by name, by number or by the engine's constant, such as %s" % str(constants.keys()[0])
147
+ ways = (
148
+ "by name, by number or by the engine's constant, such as %s" % str(constants.keys()[0])
149
+ )
148
150
  var said: String = (
149
151
  "%s.%s is an enum, and %s is none of its values: send %s %s"
150
152
  % [holder, property, word, _listed(choices), ways]
@@ -163,7 +165,10 @@ static func enum_argument_refusal(
163
165
  called: String, index: int, named: String, word: String, choices: Dictionary
164
166
  ) -> String:
165
167
  var said: String = (
166
- "%s takes the enum %s as argument %d, and %s is none of its values: send %s by name or by number"
168
+ (
169
+ "%s takes the enum %s as argument %d, and %s is none of its values: send %s by name or "
170
+ + "by number"
171
+ )
167
172
  % [called, named, index + 1, word, _listed(choices)]
168
173
  )
169
174
  var close: PackedStringArray = GdhRead.nearest(word, PackedStringArray(choices.keys()))
@@ -174,7 +179,9 @@ static func enum_argument_refusal(
174
179
 
175
180
  ## Why [param value], given as argument [param index] for the enum [param named], is none of its
176
181
  ## [param choices], or "" when it is one. The engine passes any number on.
177
- static func outside_enum_argument(index: int, named: String, value: Variant, choices: Dictionary) -> String:
182
+ static func outside_enum_argument(
183
+ index: int, named: String, value: Variant, choices: Dictionary
184
+ ) -> String:
178
185
  if typeof(value) != TYPE_INT or choices.values().has(value):
179
186
  return ""
180
187
  return (
@@ -235,7 +242,10 @@ static func outside(target: Object, declared: Dictionary, value: Variant, shown:
235
242
  var hint: int = GdhRead.as_int(declared.get("hint", PROPERTY_HINT_NONE))
236
243
  var hint_string: String = str(declared.get("hint_string", ""))
237
244
  var property: String = str(declared.get("name", ""))
238
- if hint == PROPERTY_HINT_ENUM and (typeof(value) == TYPE_STRING or typeof(value) == TYPE_STRING_NAME):
245
+ if (
246
+ hint == PROPERTY_HINT_ENUM
247
+ and (typeof(value) == TYPE_STRING or typeof(value) == TYPE_STRING_NAME)
248
+ ):
239
249
  var names: PackedStringArray = PackedStringArray(enum_values(hint_string).keys())
240
250
  if names.is_empty() or names.has(str(value)):
241
251
  return ""
@@ -308,15 +318,17 @@ static func _listed(choices: Dictionary) -> String:
308
318
  return ", ".join(listed)
309
319
 
310
320
 
311
- ## A range's end as the script wrote it: the engine's hint gives @export_range(0, 10) as 0.0 and 10.0.
321
+ ## A range's end as the script wrote it: the engine's hint gives @export_range(0, 10) as 0.0 and
322
+ ## 10.0.
312
323
  static func _bound(end: float) -> String:
313
324
  return str(int(end)) if end == floorf(end) and absf(end) < 1e15 else str(end)
314
325
 
315
326
 
316
327
  ## Puts back on [param built] what its script set as it was attached and was not among
317
- ## [param wanted], to the defaults it declares, outside the editor. Attaching runs the script's _init
318
- ## there, which the editor never runs for a script that is not a tool, so a resource_name _init chose
319
- ## was saved as if asked for. A property whose default the engine cannot report is left as made.
328
+ ## [param wanted], to the defaults it declares, outside the editor. Attaching runs the script's
329
+ ## _init there, which the editor never runs for a script that is not a tool, so a resource_name
330
+ ## _init chose was saved as if asked for. A property whose default the engine cannot report is left
331
+ ## as made.
320
332
  static func unmade(built: Resource, wanted: Dictionary) -> void:
321
333
  var attached: Variant = built.get_script()
322
334
  if Engine.is_editor_hint() or not attached is Script:
@@ -445,17 +457,25 @@ static func runs_script_code(target: Object, name: String) -> bool:
445
457
  ## the buses are read from the AudioServer, which holds the project's layout; "the engine changed or
446
458
  ## refused the value" left a caller to guess the bus did not exist.
447
459
  static func not_held(
448
- holder: String, engine_class: String, property: String, declared: Dictionary, given: Array, held: String
460
+ holder: String,
461
+ engine_class: String,
462
+ property: String,
463
+ declared: Dictionary,
464
+ given: Array,
465
+ held: String
449
466
  ) -> String:
450
467
  var value: Variant = given[0]
451
- var said: String = "%s.%s was given %s and holds %s after it was set" % [holder, property, given[1], held]
468
+ var said: String = (
469
+ "%s.%s was given %s and holds %s after it was set" % [holder, property, given[1], held]
470
+ )
452
471
  var type: int = GdhRead.as_int(declared.get("type", TYPE_NIL))
453
472
  var hint: int = GdhRead.as_int(declared.get("hint", PROPERTY_HINT_NONE))
454
473
  if hint in LAYER_NAMES and typeof(value) == TYPE_INT:
455
474
  return (
456
475
  (
457
- "%s: it is a mask of the %s layers, one bit each from layer 1 (1) to layer %d (%d), so it "
458
- + "takes 0 to %d and the engine keeps only those bits. Nothing was written."
476
+ "%s: it is a mask of the %s layers, one bit each from layer 1 (1) to layer %d "
477
+ + "(%d), so it takes 0 to %d and the engine keeps only those bits. Nothing was "
478
+ + "written."
459
479
  )
460
480
  % [
461
481
  said,
@@ -477,22 +497,28 @@ static func not_held(
477
497
  return said + ": the engine changed or refused the value, so nothing was written."
478
498
  var close: PackedStringArray = GdhRead.nearest(str(value), names)
479
499
  var nearest: String = (
480
- "%s %s" % ["is" if close.size() == 1 else "are", ", ".join(close)] if not close.is_empty() else ""
500
+ "%s %s" % ["is" if close.size() == 1 else "are", ", ".join(close)]
501
+ if not close.is_empty()
502
+ else ""
481
503
  )
482
504
  if bus:
483
505
  # Not "holds Master after it was set": the getter answers the first bus for any name the
484
506
  # layout lacks, and nothing was kept.
485
507
  return (
486
508
  (
487
- "%s.bus takes the name of one of the project's audio buses, and %s is none of them, so it "
488
- + "would play on %s; %s. project_info include audio_buses lists them, and "
489
- + "project_settings add_audio_bus adds one. Nothing was written."
509
+ "%s.bus takes the name of one of the project's audio buses, and %s is none of "
510
+ + "them, so it would play on %s; %s. project_info include audio_buses lists them, "
511
+ + "and project_settings add_audio_bus adds one. Nothing was written."
490
512
  )
491
513
  % [
492
514
  holder,
493
515
  given[1],
494
516
  AudioServer.get_bus_name(0),
495
- "the buses are " + ", ".join(names) if nearest.is_empty() else "the nearest " + nearest
517
+ (
518
+ "the buses are " + ", ".join(names)
519
+ if nearest.is_empty()
520
+ else "the nearest " + nearest
521
+ ),
496
522
  ]
497
523
  )
498
524
  return (
@@ -500,7 +526,11 @@ static func not_held(
500
526
  % [
501
527
  said,
502
528
  given[1],
503
- "it lists " + ", ".join(names) if nearest.is_empty() else "the nearest it lists " + nearest
529
+ (
530
+ "it lists " + ", ".join(names)
531
+ if nearest.is_empty()
532
+ else "the nearest it lists " + nearest
533
+ ),
504
534
  ]
505
535
  )
506
536
 
@@ -513,7 +543,9 @@ static func held_by_children(node: Node, property: String) -> String:
513
543
  var holders: PackedStringArray = []
514
544
  for child: Node in node.get_children():
515
545
  if property in child:
516
- var _added: bool = holders.append("%s (a %s)" % [root.get_path_to(child), child.get_class()])
546
+ var _added: bool = holders.append(
547
+ "%s (a %s)" % [root.get_path_to(child), child.get_class()]
548
+ )
517
549
  if holders.is_empty():
518
550
  return ""
519
551
  if holders.size() == 1:
@@ -523,14 +555,15 @@ static func held_by_children(node: Node, property: String) -> String:
523
555
 
524
556
 
525
557
  ## A sentence for each node path in [param given], by property, that names no node from
526
- ## [param node]. A path is written whatever it names, as the inspector writes one, since the node may
527
- ## be added next; a joint whose node_a named nothing then joined nothing, and no answer said so.
558
+ ## [param node]. A path is written whatever it names, as the inspector writes one, since the node
559
+ ## may be added next; a joint whose node_a named nothing then joined nothing, and no answer said so.
528
560
  static func naming_nothing(node: Node, given: Dictionary) -> Dictionary:
529
561
  var said: Dictionary = {}
530
562
  for property: String in given:
531
563
  if "/" in property or ":" in property:
532
564
  continue
533
- # What the node holds, since a path given as text is held as text until the engine stores it.
565
+ # What the node holds, since a path given as text is held as text until the engine stores
566
+ # it.
534
567
  var path: Variant = node.get(property)
535
568
  if not path is NodePath:
536
569
  continue
@@ -539,8 +572,8 @@ static func naming_nothing(node: Node, given: Dictionary) -> Dictionary:
539
572
  continue
540
573
  said[property] = (
541
574
  (
542
- "%s names no node from %s. It is written, as the editor writes one, since that node may "
543
- + "be added next; until it is, %s finds nothing."
575
+ "%s names no node from %s. It is written, as the editor writes one, since that "
576
+ + "node may be added next; until it is, %s finds nothing."
544
577
  )
545
578
  % [str(named), node.name, property]
546
579
  )
@@ -553,7 +586,10 @@ static func naming_nothing(node: Node, given: Dictionary) -> Dictionary:
553
586
  static func no_uniform(material: ShaderMaterial, property: String) -> String:
554
587
  var uniform: String = property.trim_prefix("shader_parameter/")
555
588
  if material.shader == null:
556
- return "The ShaderMaterial has no shader, so it has no parameter %s yet; set shader first." % uniform
589
+ return (
590
+ "The ShaderMaterial has no shader, so it has no parameter %s yet; set shader first."
591
+ % uniform
592
+ )
557
593
  var shader: String = material.shader.resource_path
558
594
  var named: String = shader if not shader.is_empty() else "Its shader"
559
595
  var uniforms: Array = []
@@ -1,5 +1,4 @@
1
1
  extends RefCounted
2
-
3
2
  ## Scenes and resources read from their files, by the editor's tools and by a headless engine with
4
3
  ## none connected, so a read answers the same either way.
5
4
  ##
@@ -30,7 +29,10 @@ static func scene_tree(
30
29
  if not laid.get("ok", false):
31
30
  return laid
32
31
  var nodes: Dictionary = laid["nodes"]
33
- return {"ok": true, "tree": _entry(nodes, ".", include_properties, include_defaults, depth, 0)}
32
+ return {
33
+ "ok": true,
34
+ "tree": _entry(nodes, ".", include_properties, include_defaults, depth, 0),
35
+ }
34
36
 
35
37
 
36
38
  ## The node at [param node_path] in [param scene_path] as {ok, name, type, properties}, laid as
@@ -45,7 +47,9 @@ static func scene_node(scene_path: String, node_path: String) -> Dictionary:
45
47
  if not nodes.has(path):
46
48
  return {}
47
49
  var found: Dictionary = nodes[path]
48
- return {"ok": true, "name": found["name"], "type": found["type"], "properties": found["properties"]}
50
+ return {
51
+ "ok": true, "name": found["name"], "type": found["type"], "properties": found["properties"],
52
+ }
49
53
 
50
54
 
51
55
  ## The node at [param node_path] in [param scene_path] as [method scene_node] answers it, when it is
@@ -67,7 +71,7 @@ static func scene_node_of_kind(scene_path: String, node_path: String, kind: Stri
67
71
  "ok": true,
68
72
  "name": nodes[path]["name"],
69
73
  "type": found,
70
- "properties": nodes[path]["properties"]
74
+ "properties": nodes[path]["properties"],
71
75
  }
72
76
  else:
73
77
  var hinted: String = said
@@ -79,7 +83,7 @@ static func scene_node_of_kind(scene_path: String, node_path: String, kind: Stri
79
83
  var type: String = str(nodes[at]["type"])
80
84
  if ClassDB.class_exists(type) and ClassDB.is_parent_class(type, kind):
81
85
  var _held: bool = held.append(str(at))
82
- return {"ok": false, "error": GdhRead.not_of_kind(said, node_path, found, kind, held)}
86
+ return { "ok": false, "error": GdhRead.not_of_kind(said, node_path, found, kind, held) }
83
87
 
84
88
 
85
89
  ## [param said], the refusal for [param node_path], which the scene laid as [param nodes] does not
@@ -100,35 +104,38 @@ static func _missing_in(nodes: Dictionary, said: String, node_path: String) -> S
100
104
  var children: Array[String] = nodes[at]["children"]
101
105
  for child: String in children:
102
106
  var _named: bool = names.append(str(nodes[child]["name"]))
103
- return GdhRead.missing_below(said, str(nodes["."]["name"]), reached, parts[reached.size()], names)
107
+ return GdhRead.missing_below(
108
+ said, str(nodes["."]["name"]), reached, parts[reached.size()], names
109
+ )
104
110
 
105
111
 
106
112
  ## Every node of [param scene_path] as {ok, nodes}, keyed by path, or a refusal.
107
113
  static func _laid(scene_path: String) -> Dictionary:
108
114
  if not FileAccess.file_exists(scene_path):
109
- return {"ok": false, "error": "Scene not found: " + scene_path}
115
+ return { "ok": false, "error": "Scene not found: " + scene_path }
110
116
  # Loaded without naming the type, so a resource handed in by mistake loads as what it is and the
111
117
  # refusal can say so, where asking for a PackedScene printed the loader's error and a backtrace.
112
118
  var loaded: Resource = ResourceLoader.load(scene_path, "", ResourceLoader.CACHE_MODE_IGNORE)
113
119
  if loaded == null:
114
- return {"ok": false, "error": "Failed to load %s as a scene" % scene_path}
120
+ return { "ok": false, "error": "Failed to load %s as a scene" % scene_path }
115
121
  if not loaded is PackedScene:
116
122
  var sort: String = GdhRead.with_article(loaded.get_class())
117
123
  return {
118
124
  "ok": false,
119
- "error": "%s is %s, not a scene: resource_edit read reads its properties." % [scene_path, sort]
125
+ "error":
126
+ "%s is %s, not a scene: resource_edit read reads its properties." % [scene_path, sort],
120
127
  }
121
128
  var packed: PackedScene = loaded
122
129
  var nodes: Dictionary = {}
123
130
  var refused: String = _lay(packed.get_state(), ".", nodes, [scene_path], packed)
124
131
  if not refused.is_empty():
125
- return {"ok": false, "error": refused}
132
+ return { "ok": false, "error": refused }
126
133
  if not nodes.has("."):
127
- return {"ok": false, "error": "%s holds no nodes" % scene_path}
134
+ return { "ok": false, "error": "%s holds no nodes" % scene_path }
128
135
  var base: SceneState = packed.get_state().get_base_scene_state()
129
136
  if base != null:
130
137
  nodes["."]["inherits"] = base.get_path()
131
- return {"ok": true, "nodes": nodes}
138
+ return { "ok": true, "nodes": nodes }
132
139
 
133
140
 
134
141
  ## Lays the nodes of [param state] into [param nodes] under [param prefix], keyed by their path
@@ -152,8 +159,8 @@ static func _lay(
152
159
  var path: String = _joined(prefix, str(state.get_node_path(index)))
153
160
  var recovered: bool = false
154
161
  if not nodes.has(path) and index > 0 and _overrides(state, index) and ids[index] >= 0:
155
- # The engine finds an entry whose node was renamed or moved in the scene it comes from by
156
- # the node's unique_id, and keeps the node's new name.
162
+ # The engine finds an entry whose node was renamed or moved in the scene it comes from
163
+ # by the node's unique_id, and keeps the node's new name.
157
164
  var parent: String = _joined(prefix, str(state.get_node_path(index, true)))
158
165
  var found: String = _by_id(nodes, _owner_of(nodes, parent, prefix), ids[index])
159
166
  recovered = not found.is_empty()
@@ -164,7 +171,9 @@ static func _lay(
164
171
  var instance: PackedScene = state.get_node_instance(index)
165
172
  if instance != null:
166
173
  if within.has(instance.resource_path):
167
- return "%s instances %s, which holds it" % [within.back(), instance.resource_path]
174
+ return (
175
+ "%s instances %s, which holds it" % [within.back(), instance.resource_path]
176
+ )
168
177
  var refused: String = _lay(
169
178
  instance.get_state(), path, nodes, within + [instance.resource_path]
170
179
  )
@@ -178,15 +187,16 @@ static func _lay(
178
187
  nodes[path] = _made("InstancePlaceholder")
179
188
  nodes[path]["instanceOf"] = state.get_node_instance_placeholder(index)
180
189
  elif str(state.get_node_type(index)).is_empty():
181
- # An entry for a node of an instance that no longer has it, which the engine skips too.
190
+ # An entry for a node of an instance that no longer has it, which the engine skips
191
+ # too.
182
192
  continue
183
193
  else:
184
194
  nodes[path] = _made(str(state.get_node_type(index)))
185
195
  nodes[path]["madeHere"] = loaded != null
186
196
  if ids[index] >= 0:
187
197
  nodes[path]["uniqueId"] = ids[index]
188
- # Laid at the root with no scene handed in is a scene the one being read inherits, and the
189
- # deepest is laid first, so this is the file that makes the node.
198
+ # Laid at the root with no scene handed in is a scene the one being read inherits, and
199
+ # the deepest is laid first, so this is the file that makes the node.
190
200
  if prefix == "." and loaded == null:
191
201
  nodes[path]["inheritedFrom"] = state.get_path()
192
202
  # The name is the state's even for an entry laid already, since an inherited scene names its
@@ -251,8 +261,8 @@ static func _editable_in(scene_path: String, given_scene: PackedScene = null) ->
251
261
 
252
262
 
253
263
  ## The unique_id of each node entry in the text scene at [param scene_path], in the order its state
254
- ## holds them, -1 where an entry has none. All -1 for a binary scene, and for a file whose entries do
255
- ## not number [param count], since SceneState does not give the ids to a script.
264
+ ## holds them, -1 where an entry has none. All -1 for a binary scene, and for a file whose entries
265
+ ## do not number [param count], since SceneState does not give the ids to a script.
256
266
  static func _unique_ids(scene_path: String, count: int) -> Array[int]:
257
267
  var ids: Array[int] = []
258
268
  var _sized: int = ids.resize(count)
@@ -289,8 +299,9 @@ static func _owner_of(nodes: Dictionary, parent: String, prefix: String) -> Stri
289
299
  return at if nodes.has(at) else prefix
290
300
 
291
301
 
292
- ## The path of the node [param owner] owns whose unique_id is [param id], or "": one under an instance
293
- ## nested below [param owner] belongs to that instance's file, whose ids are numbered apart.
302
+ ## The path of the node [param owner] owns whose unique_id is [param id], or "": one under an
303
+ ## instance nested below [param owner] belongs to that instance's file, whose ids are numbered
304
+ ## apart.
294
305
  static func _by_id(nodes: Dictionary, owner: String, id: int) -> String:
295
306
  for path: String in nodes:
296
307
  if path == owner or not (owner == "." or path.begins_with(owner + "/")):
@@ -307,7 +318,7 @@ static func _by_id(nodes: Dictionary, owner: String, id: int) -> String:
307
318
  static func _made(type: String) -> Dictionary:
308
319
  var children: Array[String] = []
309
320
  var groups: Array[String] = []
310
- return {"name": "", "type": type, "properties": {}, "children": children, "groups": groups}
321
+ return { "name": "", "type": type, "properties": {}, "children": children, "groups": groups }
311
322
 
312
323
 
313
324
  ## Puts [param path] among [param parent]'s children, at [param at] when the file says where (a node
@@ -342,7 +353,9 @@ static func _entry(
342
353
  ) -> Dictionary:
343
354
  var node: Dictionary = nodes[path]
344
355
  var children: Array[Dictionary] = []
345
- var data: Dictionary = {"name": node["name"], "type": node["type"], "path": path, "children": children}
356
+ var data: Dictionary = {
357
+ "name": node["name"], "type": node["type"], "path": path, "children": children,
358
+ }
346
359
  # The root's file is the scene being read, so only another node's names a second scene.
347
360
  if path != "." and node.has("instanceOf"):
348
361
  data["instanceOf"] = node["instanceOf"]
@@ -369,7 +382,8 @@ static func _entry(
369
382
  if cells >= 0:
370
383
  data["cellCount"] = cells
371
384
  data["cellsListedBy"] = (
372
- "scene_node get with nodePath %s, which lists them as set_tilemap_cells takes them" % path
385
+ "scene_node get with nodePath %s, which lists them as set_tilemap_cells takes them"
386
+ % path
373
387
  )
374
388
  if not node.get("madeHere", false):
375
389
  var kept: Array = node.get("setHere", [])
@@ -383,14 +397,16 @@ static func _entry(
383
397
  data["childrenNotListed"] = below.size()
384
398
  return data
385
399
  for child: String in below:
386
- children.append(_entry(nodes, child, include_properties, include_defaults, depth, current_depth + 1))
400
+ children.append(
401
+ _entry(nodes, child, include_properties, include_defaults, depth, current_depth + 1)
402
+ )
387
403
  return data
388
404
 
389
405
 
390
406
  ## How many cells a TileMapLayer or TileMap of [param type] holds under the values [param given], or
391
- ## -1 when it is another node or the file sets none of its cells. The file keeps them as packed bytes,
392
- ## which a read of the tree answered with alone, so a caller decoded the base64 to learn what was
393
- ## painted. Only cells the file sets are counted: an instance's come from its own scene.
407
+ ## -1 when it is another node or the file sets none of its cells. The file keeps them as packed
408
+ ## bytes, which a read of the tree answered with alone, so a caller decoded the base64 to learn what
409
+ ## was painted. Only cells the file sets are counted: an instance's come from its own scene.
394
410
  static func _cell_count(type: String, given: Dictionary) -> int:
395
411
  if not ClassDB.class_exists(type) or not ClassDB.can_instantiate(type):
396
412
  return -1
@@ -400,7 +416,10 @@ static func _cell_count(type: String, given: Dictionary) -> int:
400
416
  var painted: bool = false
401
417
  for property: Variant in given:
402
418
  var named: String = str(property)
403
- if named == "tile_map_data" or (named.begins_with("layer_") and named.ends_with("/tile_data")):
419
+ if (
420
+ named == "tile_map_data"
421
+ or (named.begins_with("layer_") and named.ends_with("/tile_data"))
422
+ ):
404
423
  painted = true
405
424
  if not painted:
406
425
  return -1
@@ -439,7 +458,10 @@ static func _stored(type: String, given: Dictionary, include_defaults: bool) ->
439
458
  if script != null:
440
459
  for declared: Dictionary in script.get_script_property_list():
441
460
  var property: String = str(declared.get("name", ""))
442
- if not property.is_empty() and GdhRead.as_int(declared.get("usage", 0)) & PROPERTY_USAGE_STORAGE:
461
+ if (
462
+ not property.is_empty()
463
+ and GdhRead.as_int(declared.get("usage", 0)) & PROPERTY_USAGE_STORAGE
464
+ ):
443
465
  scripted[property] = script.get_property_default_value(property)
444
466
  var values: Dictionary = {}
445
467
  var defaults: Dictionary = {}
@@ -451,7 +473,10 @@ static func _stored(type: String, given: Dictionary, include_defaults: bool) ->
451
473
  bare.set(str(property), given[property])
452
474
  for declared: Dictionary in bare.get_property_list():
453
475
  var property: String = str(declared.get("name", ""))
454
- if not property.is_empty() and GdhRead.as_int(declared.get("usage", 0)) & PROPERTY_USAGE_STORAGE:
476
+ if (
477
+ not property.is_empty()
478
+ and GdhRead.as_int(declared.get("usage", 0)) & PROPERTY_USAGE_STORAGE
479
+ ):
455
480
  values[property] = bare.get(property)
456
481
  defaults[property] = plain.get(property)
457
482
  for made: Object in [bare, plain]:
@@ -476,7 +501,7 @@ static func _stored(type: String, given: Dictionary, include_defaults: bool) ->
476
501
  left_out += 1
477
502
  continue
478
503
  answered[property] = serialiser.serialize_value(values[property])
479
- return {"properties": answered, "left_out": left_out}
504
+ return { "properties": answered, "left_out": left_out }
480
505
 
481
506
 
482
507
  ## What a resource file holds, in the form modify takes, so a value read here can be written back.
@@ -488,10 +513,13 @@ static func _stored(type: String, given: Dictionary, include_defaults: bool) ->
488
513
  static func resource(res_path: String, include_defaults: bool) -> Dictionary:
489
514
  var file: String = res_path.get_slice("::", 0)
490
515
  if not FileAccess.file_exists(file):
491
- return {"ok": false, "error": GdhFileWalk.new().with_nearest_files("No resource at " + file, file)}
516
+ return {
517
+ "ok": false,
518
+ "error": GdhFileWalk.new().with_nearest_files("No resource at " + file, file),
519
+ }
492
520
  var whole: Resource = ResourceLoader.load(file, "", ResourceLoader.CACHE_MODE_IGNORE)
493
521
  if whole == null:
494
- return {"ok": false, "error": "%s did not load as a resource." % file}
522
+ return { "ok": false, "error": "%s did not load as a resource." % file }
495
523
  # The file's resource is held until the read is done, since what it keeps can depend on it: a
496
524
  # TileSet that goes unlinks its sources, and an atlas source with no TileSet lists none of its
497
525
  # tiles' physics, navigation or custom data.
@@ -500,14 +528,20 @@ static func resource(res_path: String, include_defaults: bool) -> Dictionary:
500
528
  var id: String = res_path.trim_prefix(file + "::")
501
529
  var inner: Resource = _kept_in(whole, file, id, {})
502
530
  if inner == null:
503
- return {"ok": false, "error": "%s keeps no resource with the id %s." % [file, id]}
531
+ return { "ok": false, "error": "%s keeps no resource with the id %s." % [file, id] }
504
532
  loaded = inner
505
533
  # A scene's own properties are its packed bundle, which says nothing a caller can use.
506
534
  if loaded is PackedScene:
507
535
  return {
508
536
  "ok": false,
509
537
  "error":
510
- "%s is a scene: scene_tree reads its nodes, and scene_node get one node's properties." % res_path
538
+ (
539
+ (
540
+ "%s is a scene: scene_tree reads its nodes, and scene_node get one node's "
541
+ + "properties."
542
+ )
543
+ % res_path
544
+ ),
511
545
  }
512
546
 
513
547
  var script: Script = loaded.get_script()
@@ -525,13 +559,17 @@ static func resource(res_path: String, include_defaults: bool) -> Dictionary:
525
559
  untooled and file.ends_with(".tres") and not GdhShapes.STORED_APART.has(loaded.get_class())
526
560
  )
527
561
  var set_in_file: Dictionary = (
528
- _names_set_in(FileAccess.get_file_as_string(file), res_path.trim_prefix(file).trim_prefix("::"))
562
+ _names_set_in(
563
+ FileAccess.get_file_as_string(file), res_path.trim_prefix(file).trim_prefix("::")
564
+ )
529
565
  if from_file
530
566
  else {}
531
567
  )
532
568
  # A Curve's points are read off one with none, since the engine has no default for point_0.
533
569
  var fresh: Object = (
534
- ClassDB.instantiate(loaded.get_class()) if GdhShapes.STORED_APART.has(loaded.get_class()) else null
570
+ ClassDB.instantiate(loaded.get_class())
571
+ if GdhShapes.STORED_APART.has(loaded.get_class())
572
+ else null
535
573
  )
536
574
  for p: Dictionary in GdhShapes.read_properties(loaded):
537
575
  var property: String = str(p.get("name", ""))
@@ -554,7 +592,10 @@ static func resource(res_path: String, include_defaults: bool) -> Dictionary:
554
592
  continue
555
593
  properties[property] = serialiser.serialize_value(value)
556
594
  var answer: Dictionary = {
557
- "ok": true, "resourcePath": res_path, "resourceType": loaded.get_class(), "properties": properties
595
+ "ok": true,
596
+ "resourcePath": res_path,
597
+ "resourceType": loaded.get_class(),
598
+ "properties": properties,
558
599
  }
559
600
  if script != null:
560
601
  answer["script"] = script.resource_path
@@ -566,8 +607,8 @@ static func resource(res_path: String, include_defaults: bool) -> Dictionary:
566
607
  return answer
567
608
 
568
609
 
569
- ## The names the [code][resource][/code] section of [param text], a .tres file, sets, or those of the
570
- ## embedded resource with the id [param id] when one is given, as a set.
610
+ ## The names the [code][resource][/code] section of [param text], a .tres file, sets, or those of
611
+ ## the embedded resource with the id [param id] when one is given, as a set.
571
612
  static func _names_set_in(text: String, id: String) -> Dictionary:
572
613
  var names: Dictionary = {}
573
614
  var inside: bool = false
@@ -23,12 +23,15 @@ static func missing_reason(path: String) -> String:
23
23
  if id == ResourceUID.INVALID_ID or not ResourceUID.has_id(id):
24
24
  return (
25
25
  path
26
- + " does not resolve: no file in the project's uid cache has it, so the file has gone or the"
27
- + " project has not been imported yet (project_import refresh_uids imports it)"
26
+ + " does not resolve: no file in the project's uid cache has it, so the file has "
27
+ + "gone or the project has not been imported yet (project_import refresh_uids "
28
+ + "imports it)"
28
29
  )
29
30
  var resolved: String = ResourceUID.get_id_path(id)
30
31
  return (
31
- "" if FileAccess.file_exists(resolved) else path + " names " + resolved + ", which does not exist"
32
+ ""
33
+ if FileAccess.file_exists(resolved)
34
+ else path + " names " + resolved + ", which does not exist"
32
35
  )
33
36
  return "" if FileAccess.file_exists(path) else path + " does not exist"
34
37
 
@@ -41,7 +44,9 @@ func with_nearest_files(said: String, path: String) -> String:
41
44
  # One the refusal names is the file it refuses, as a script given for a scene is. Word by word,
42
45
  # since res://brain.gd is inside res://brain.gdd.
43
46
  var named: Array[String] = []
44
- for word: String in said.replace("\n", " ").replace(",", " ").replace(";", " ").split(" ", false):
47
+ for word: String in said.replace("\n", " ").replace(",", " ").replace(";", " ").split(
48
+ " ", false
49
+ ):
45
50
  named.append(word.rstrip(".:"))
46
51
  var namesakes: Array[String] = []
47
52
  for file: String in _namesakes(path):
@@ -78,7 +83,9 @@ func with_nearest_files(said: String, path: String) -> String:
78
83
  )
79
84
  if files.size() <= GdhRead.NAMED_CHILDREN:
80
85
  return "%s. The project's .%s files are %s." % [said, extension, ", ".join(files)]
81
- return "%s. None of the project's %d .%s files is named like it." % [said, files.size(), extension]
86
+ return (
87
+ "%s. None of the project's %d .%s files is named like it." % [said, files.size(), extension]
88
+ )
82
89
 
83
90
 
84
91
  # The files in [param path]'s folder named as it is with another extension, leaving out the import