gdharness 1.3.0 → 1.3.1

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 (68) hide show
  1. package/build/cli.js +14 -13
  2. package/build/godot/addons/gdharness_editor/animation_reads.gd +7 -19
  3. package/build/godot/addons/gdharness_editor/bridge_client.gd +8 -8
  4. package/build/godot/addons/gdharness_editor/file_reads.gd +60 -25
  5. package/build/godot/addons/gdharness_editor/headless_check.gd +7 -7
  6. package/build/godot/addons/gdharness_editor/plugin.gd +6 -6
  7. package/build/godot/addons/gdharness_editor/property_values.gd +120 -53
  8. package/build/godot/addons/gdharness_editor/reading.gd +28 -0
  9. package/build/godot/addons/gdharness_editor/scene_file.gd +28 -23
  10. package/build/godot/addons/gdharness_editor/serialisation.gd +45 -94
  11. package/build/godot/addons/gdharness_editor/tool_executor.gd +24 -24
  12. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +52 -41
  13. package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +4 -4
  14. package/build/godot/addons/gdharness_editor/tools/play_tools.gd +2 -2
  15. package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +14 -14
  16. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +48 -41
  17. package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +17 -17
  18. package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +14 -12
  19. package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +7 -7
  20. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +81 -77
  21. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +4 -4
  22. package/build/godot/addons/gdharness_editor/value_shapes.gd +111 -0
  23. package/build/godot/addons/gdharness_editor/value_shapes.gd.uid +1 -0
  24. package/build/godot/addons/gdharness_runtime/reading.gd +28 -0
  25. package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +18 -18
  26. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +29 -29
  27. package/build/godot/addons/gdharness_runtime/runtime_capture.gd +21 -18
  28. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +86 -80
  29. package/build/godot/addons/gdharness_runtime/runtime_input.gd +65 -64
  30. package/build/godot/addons/gdharness_runtime/runtime_items.gd +6 -6
  31. package/build/godot/addons/gdharness_runtime/runtime_menus.gd +8 -8
  32. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +6 -6
  33. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +10 -10
  34. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +7 -7
  35. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +41 -41
  36. package/build/godot/addons/gdharness_runtime/runtime_says.gd +3 -3
  37. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +33 -33
  38. package/build/godot/addons/gdharness_runtime/runtime_typing.gd +20 -20
  39. package/build/godot/addons/gdharness_runtime/runtime_values.gd +25 -24
  40. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +56 -50
  41. package/build/godot/addons/gdharness_runtime/serialisation.gd +45 -94
  42. package/build/godot/addons/gdharness_runtime/value_shapes.gd +111 -0
  43. package/build/godot/addons/gdharness_runtime/value_shapes.gd.uid +1 -0
  44. package/build/godot/operations/animation_reads.gd +7 -19
  45. package/build/godot/operations/audio_buses.gd +10 -10
  46. package/build/godot/operations/class_cache.gd +16 -16
  47. package/build/godot/operations/classdb_queries.gd +12 -12
  48. package/build/godot/operations/dependencies.gd +33 -29
  49. package/build/godot/operations/editor_tools.gd +12 -12
  50. package/build/godot/operations/export_presets.gd +10 -8
  51. package/build/godot/operations/file_reads.gd +60 -25
  52. package/build/godot/operations/gdscript_analysis.gd +20 -20
  53. package/build/godot/operations/gdscript_authoring.gd +17 -15
  54. package/build/godot/operations/godot_operations.gd +64 -63
  55. package/build/godot/operations/import_pipeline.gd +20 -20
  56. package/build/godot/operations/input_actions.gd +17 -17
  57. package/build/godot/operations/logger.gd +1 -1
  58. package/build/godot/operations/plugins.gd +8 -8
  59. package/build/godot/operations/project_config.gd +24 -17
  60. package/build/godot/operations/project_diagnostics.gd +9 -9
  61. package/build/godot/operations/property_values.gd +120 -53
  62. package/build/godot/operations/reading.gd +28 -0
  63. package/build/godot/operations/rename_checks.gd +3 -3
  64. package/build/godot/operations/resource_files.gd +5 -5
  65. package/build/godot/operations/script_check.gd +7 -7
  66. package/build/godot/operations/serialisation.gd +45 -94
  67. package/build/godot/operations/value_shapes.gd +111 -0
  68. package/package.json +1 -1
@@ -8,7 +8,8 @@ extends RefCounted
8
8
  ## before: the same Vector2 came back three ways depending on which tool was asked, and a caller
9
9
  ## reading a property off the editor could not feed it back to the game.
10
10
 
11
- const Read = preload("reading.gd")
11
+ const GdhRead = preload("reading.gd")
12
+ const GdhShapes = preload("value_shapes.gd")
12
13
 
13
14
  # What the engine carries from one to another without complaint, which is what a value written to a
14
15
  # property or handed to a parameter may arrive as. Numbers include bool because the engine counts it
@@ -120,35 +121,6 @@ const BUILDERS: Dictionary = {
120
121
  "Dictionary": "_build_dictionary",
121
122
  }
122
123
 
123
- # What each tag has to carry before it is built. A tag naming a type whose keys are not there is a
124
- # tag somebody wrote by mistake or wrote for a different shape, and building one out of defaults
125
- # answers with a Transform2D of zeros where the caller meant something else entirely. Unbuilt, it
126
- # comes back as it arrived, and whoever asked can read it against the type they were expecting.
127
- const REQUIRED: Dictionary = {
128
- "Vector2": [["x", "y"]],
129
- "Vector2i": [["x", "y"]],
130
- "Vector3": [["x", "y", "z"]],
131
- "Vector3i": [["x", "y", "z"]],
132
- "Vector4": [["x", "y", "z", "w"]],
133
- "Vector4i": [["x", "y", "z", "w"]],
134
- "Rect2": [["position", "size"], ["x", "y", "width", "height"]],
135
- "Rect2i": [["position", "size"], ["x", "y", "width", "height"]],
136
- "Plane": [["normal", "d"]],
137
- "Quaternion": [["x", "y", "z", "w"]],
138
- "AABB": [["position", "size"]],
139
- "Basis": [["x", "y", "z"]],
140
- "Transform2D": [["x", "y", "origin"]],
141
- "Transform3D": [["basis", "origin"]],
142
- "Projection": [["x", "y", "z", "w"]],
143
- "Color": [["r", "g", "b"]],
144
- "NodePath": [["path"]],
145
- "PackedByteArray": [["base64"]],
146
- "float": [["value"]],
147
- "int": [["value"]],
148
- "RID": [["id"]],
149
- "Dictionary": [["entries"]],
150
- }
151
-
152
124
 
153
125
  # Converts a Godot value into something JSON can carry. A type with no entry in the table
154
126
  # passes through as itself, which is what the JSON-native ones want.
@@ -246,8 +218,8 @@ func deserialize_value(value: Variant) -> Variant:
246
218
  # under the target project's warning levels, so one such project lost every headless call.
247
219
  var tag: String = str(fields["_type"])
248
220
  var builder: String = BUILDERS.get(tag, "")
249
- var needed: Array = REQUIRED.get(tag, [])
250
- if builder.is_empty() or not _carries(fields, needed):
221
+ var spare: Array = GdhShapes.spare(fields, tag)
222
+ if builder.is_empty() or not spare.any(func(left: Array) -> bool: return left.is_empty()):
251
223
  return fields
252
224
  if tag == "float" and str(fields["value"]) not in ["inf", "-inf", "nan"]:
253
225
  return fields
@@ -430,6 +402,11 @@ func fitted(value: Variant, type: int) -> Variant:
430
402
  if rebuilt is Array and LIST_TYPES.has(type):
431
403
  return type_convert(rebuilt, type)
432
404
 
405
+ # The inspector and every colour picker give a colour as its html code. Anything else stays the
406
+ # text it is, for the refusal to name.
407
+ if type == TYPE_COLOR and rebuilt is String and Color.html_is_valid(str(rebuilt)):
408
+ return Color.html(str(rebuilt))
409
+
433
410
  var simple: Array[int] = [TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING]
434
411
  if not simple.has(type) or not simple.has(typeof(rebuilt)):
435
412
  return rebuilt
@@ -441,7 +418,7 @@ func fitted(value: Variant, type: int) -> Variant:
441
418
 
442
419
  if rebuilt is String and type != TYPE_STRING:
443
420
  var text: String = rebuilt
444
- var parsed: Variant = Read.json_or_null(text)
421
+ var parsed: Variant = GdhRead.json_or_null(text)
445
422
  # A string that does not read as the type wanted is handed back as the string it is, so
446
423
  # whoever asked can refuse it. type_convert answers 0 for "not an index" and true for any
447
424
  # text at all, and a caller who sent a word got back a number they never sent: get_child
@@ -461,7 +438,7 @@ func fitted(value: Variant, type: int) -> Variant:
461
438
  static func inexact(given: Variant, type: int) -> String:
462
439
  if type != TYPE_INT or (typeof(given) != TYPE_FLOAT and typeof(given) != TYPE_INT):
463
440
  return ""
464
- var number: float = Read.as_float(given)
441
+ var number: float = GdhRead.as_float(given)
465
442
  if not is_finite(number) or absf(number) < EXACT:
466
443
  return ""
467
444
  return (
@@ -474,34 +451,6 @@ static func inexact(given: Variant, type: int) -> String:
474
451
  )
475
452
 
476
453
 
477
- ## How a value of [param type] is written to be read as one, for a refusal to name, or empty for a
478
- ## type that is not built from fields. A refusal naming only the two types left a caller to find
479
- ## the shape in the description of another op.
480
- static func written_as(type: int) -> String:
481
- var tag: String = type_string(type)
482
- var alternatives: Array = REQUIRED.get(tag, [])
483
- if alternatives.is_empty() or tag in ["float", "int", "Dictionary"]:
484
- return ""
485
- var keys: Array = alternatives[0]
486
- var parts: Array[String] = []
487
- for key: Variant in keys:
488
- parts.append('"%s": ...' % key)
489
- return "{%s}" % ", ".join(parts)
490
-
491
-
492
- ## Whether [param fields] carries every key of any one of [param alternatives].
493
- ##
494
- ## More than one spelling because a rectangle has two: the two corners it is answered with, and the
495
- ## four numbers the editor's own tools answered with before the serialisers were made one, which a
496
- ## caller may have kept.
497
- func _carries(fields: Dictionary, alternatives: Array) -> bool:
498
- for alternative: Variant in alternatives:
499
- var keys: Array = alternative
500
- if keys.all(func(key: Variant) -> bool: return fields.has(key)):
501
- return true
502
- return false
503
-
504
-
505
454
  func _serialize_nil(_value: Variant) -> Variant:
506
455
  return null
507
456
 
@@ -769,42 +718,44 @@ func _describe_object(value: Object) -> Dictionary:
769
718
 
770
719
 
771
720
  func _build_vector2(fields: Dictionary) -> Vector2:
772
- return Vector2(Read.as_float(fields.get("x", 0)), Read.as_float(fields.get("y", 0)))
721
+ return Vector2(GdhRead.as_float(fields.get("x", 0)), GdhRead.as_float(fields.get("y", 0)))
773
722
 
774
723
 
775
724
  func _build_vector2i(fields: Dictionary) -> Vector2i:
776
- return Vector2i(Read.as_int(fields.get("x", 0)), Read.as_int(fields.get("y", 0)))
725
+ return Vector2i(GdhRead.as_int(fields.get("x", 0)), GdhRead.as_int(fields.get("y", 0)))
777
726
 
778
727
 
779
728
  func _build_vector3(fields: Dictionary) -> Vector3:
780
729
  return Vector3(
781
- Read.as_float(fields.get("x", 0)),
782
- Read.as_float(fields.get("y", 0)),
783
- Read.as_float(fields.get("z", 0))
730
+ GdhRead.as_float(fields.get("x", 0)),
731
+ GdhRead.as_float(fields.get("y", 0)),
732
+ GdhRead.as_float(fields.get("z", 0))
784
733
  )
785
734
 
786
735
 
787
736
  func _build_vector3i(fields: Dictionary) -> Vector3i:
788
737
  return Vector3i(
789
- Read.as_int(fields.get("x", 0)), Read.as_int(fields.get("y", 0)), Read.as_int(fields.get("z", 0))
738
+ GdhRead.as_int(fields.get("x", 0)),
739
+ GdhRead.as_int(fields.get("y", 0)),
740
+ GdhRead.as_int(fields.get("z", 0))
790
741
  )
791
742
 
792
743
 
793
744
  func _build_vector4(fields: Dictionary) -> Vector4:
794
745
  return Vector4(
795
- Read.as_float(fields.get("x", 0)),
796
- Read.as_float(fields.get("y", 0)),
797
- Read.as_float(fields.get("z", 0)),
798
- Read.as_float(fields.get("w", 0))
746
+ GdhRead.as_float(fields.get("x", 0)),
747
+ GdhRead.as_float(fields.get("y", 0)),
748
+ GdhRead.as_float(fields.get("z", 0)),
749
+ GdhRead.as_float(fields.get("w", 0))
799
750
  )
800
751
 
801
752
 
802
753
  func _build_vector4i(fields: Dictionary) -> Vector4i:
803
754
  return Vector4i(
804
- Read.as_int(fields.get("x", 0)),
805
- Read.as_int(fields.get("y", 0)),
806
- Read.as_int(fields.get("z", 0)),
807
- Read.as_int(fields.get("w", 0))
755
+ GdhRead.as_int(fields.get("x", 0)),
756
+ GdhRead.as_int(fields.get("y", 0)),
757
+ GdhRead.as_int(fields.get("z", 0)),
758
+ GdhRead.as_int(fields.get("w", 0))
808
759
  )
809
760
 
810
761
 
@@ -813,10 +764,10 @@ func _build_vector4i(fields: Dictionary) -> Vector4i:
813
764
  func _build_rect2(fields: Dictionary) -> Rect2:
814
765
  if not fields.has("position"):
815
766
  return Rect2(
816
- Read.as_float(fields.get("x", 0)),
817
- Read.as_float(fields.get("y", 0)),
818
- Read.as_float(fields.get("width", 0)),
819
- Read.as_float(fields.get("height", 0))
767
+ GdhRead.as_float(fields.get("x", 0)),
768
+ GdhRead.as_float(fields.get("y", 0)),
769
+ GdhRead.as_float(fields.get("width", 0)),
770
+ GdhRead.as_float(fields.get("height", 0))
820
771
  )
821
772
  return Rect2(_vector2_at(fields, "position"), _vector2_at(fields, "size"))
822
773
 
@@ -824,24 +775,24 @@ func _build_rect2(fields: Dictionary) -> Rect2:
824
775
  func _build_rect2i(fields: Dictionary) -> Rect2i:
825
776
  if not fields.has("position"):
826
777
  return Rect2i(
827
- Read.as_int(fields.get("x", 0)),
828
- Read.as_int(fields.get("y", 0)),
829
- Read.as_int(fields.get("width", 0)),
830
- Read.as_int(fields.get("height", 0))
778
+ GdhRead.as_int(fields.get("x", 0)),
779
+ GdhRead.as_int(fields.get("y", 0)),
780
+ GdhRead.as_int(fields.get("width", 0)),
781
+ GdhRead.as_int(fields.get("height", 0))
831
782
  )
832
783
  return Rect2i(_vector2i_at(fields, "position"), _vector2i_at(fields, "size"))
833
784
 
834
785
 
835
786
  func _build_plane(fields: Dictionary) -> Plane:
836
- return Plane(_vector3_at(fields, "normal"), Read.as_float(fields.get("d", 0)))
787
+ return Plane(_vector3_at(fields, "normal"), GdhRead.as_float(fields.get("d", 0)))
837
788
 
838
789
 
839
790
  func _build_quaternion(fields: Dictionary) -> Quaternion:
840
791
  return Quaternion(
841
- Read.as_float(fields.get("x", 0)),
842
- Read.as_float(fields.get("y", 0)),
843
- Read.as_float(fields.get("z", 0)),
844
- Read.as_float(fields.get("w", 0))
792
+ GdhRead.as_float(fields.get("x", 0)),
793
+ GdhRead.as_float(fields.get("y", 0)),
794
+ GdhRead.as_float(fields.get("z", 0)),
795
+ GdhRead.as_float(fields.get("w", 0))
845
796
  )
846
797
 
847
798
 
@@ -881,10 +832,10 @@ func _build_projection(fields: Dictionary) -> Projection:
881
832
 
882
833
  func _build_color(fields: Dictionary) -> Color:
883
834
  return Color(
884
- Read.as_float(fields.get("r", 0)),
885
- Read.as_float(fields.get("g", 0)),
886
- Read.as_float(fields.get("b", 0)),
887
- Read.as_float(fields.get("a", 1), 1.0)
835
+ GdhRead.as_float(fields.get("r", 0)),
836
+ GdhRead.as_float(fields.get("g", 0)),
837
+ GdhRead.as_float(fields.get("b", 0)),
838
+ GdhRead.as_float(fields.get("a", 1), 1.0)
888
839
  )
889
840
 
890
841
 
@@ -897,7 +848,7 @@ func _build_bytes(fields: Dictionary) -> PackedByteArray:
897
848
 
898
849
 
899
850
  func _build_float(fields: Dictionary) -> float:
900
- return Read.as_float(fields)
851
+ return GdhRead.as_float(fields)
901
852
 
902
853
 
903
854
  func _build_int(fields: Dictionary) -> int:
@@ -5,25 +5,25 @@ extends Node
5
5
  ## preloaded rather than looked up on disk at runtime, so a missing one fails to parse here
6
6
  ## instead of leaving a command silently unanswered.
7
7
 
8
- const SceneTools = preload("tools/scene_tools.gd")
9
- const ResourceTools = preload("tools/resource_tools.gd")
10
- const AnimationTools = preload("tools/animation_tools.gd")
11
- const PlayTools = preload("tools/play_tools.gd")
12
- const ClassTools = preload("tools/class_tools.gd")
13
- const SettingsTools = preload("tools/settings_tools.gd")
14
- const FilesystemTools = preload("tools/filesystem_tools.gd")
15
- const ProfileTools = preload("tools/profile_tools.gd")
8
+ const GdhSceneTools = preload("tools/scene_tools.gd")
9
+ const GdhResourceTools = preload("tools/resource_tools.gd")
10
+ const GdhAnimationTools = preload("tools/animation_tools.gd")
11
+ const GdhPlayTools = preload("tools/play_tools.gd")
12
+ const GdhClassTools = preload("tools/class_tools.gd")
13
+ const GdhSettingsTools = preload("tools/settings_tools.gd")
14
+ const GdhFilesystemTools = preload("tools/filesystem_tools.gd")
15
+ const GdhProfileTools = preload("tools/profile_tools.gd")
16
16
 
17
17
  var _editor_plugin: EditorPlugin = null
18
18
 
19
- var _scene_tools: SceneTools = null
20
- var _resource_tools: ResourceTools = null
21
- var _animation_tools: AnimationTools = null
22
- var _play_tools: PlayTools = null
23
- var _class_tools: ClassTools = null
24
- var _settings_tools: SettingsTools = null
25
- var _filesystem_tools: FilesystemTools = null
26
- var _profile_tools: ProfileTools = null
19
+ var _scene_tools: GdhSceneTools = null
20
+ var _resource_tools: GdhResourceTools = null
21
+ var _animation_tools: GdhAnimationTools = null
22
+ var _play_tools: GdhPlayTools = null
23
+ var _class_tools: GdhClassTools = null
24
+ var _settings_tools: GdhSettingsTools = null
25
+ var _filesystem_tools: GdhFilesystemTools = null
26
+ var _profile_tools: GdhProfileTools = null
27
27
 
28
28
  var _tool_map: Dictionary = {}
29
29
  var _initialized: bool = false
@@ -46,35 +46,35 @@ func _init_tools() -> void:
46
46
  return
47
47
  _initialized = true
48
48
 
49
- _scene_tools = SceneTools.new()
49
+ _scene_tools = GdhSceneTools.new()
50
50
  _scene_tools.name = "SceneTools"
51
51
  add_child(_scene_tools)
52
52
 
53
- _resource_tools = ResourceTools.new()
53
+ _resource_tools = GdhResourceTools.new()
54
54
  _resource_tools.name = "ResourceTools"
55
55
  add_child(_resource_tools)
56
56
 
57
- _animation_tools = AnimationTools.new()
57
+ _animation_tools = GdhAnimationTools.new()
58
58
  _animation_tools.name = "AnimationTools"
59
59
  add_child(_animation_tools)
60
60
 
61
- _play_tools = PlayTools.new()
61
+ _play_tools = GdhPlayTools.new()
62
62
  _play_tools.name = "PlayTools"
63
63
  add_child(_play_tools)
64
64
 
65
- _class_tools = ClassTools.new()
65
+ _class_tools = GdhClassTools.new()
66
66
  _class_tools.name = "ClassTools"
67
67
  add_child(_class_tools)
68
68
 
69
- _settings_tools = SettingsTools.new()
69
+ _settings_tools = GdhSettingsTools.new()
70
70
  _settings_tools.name = "SettingsTools"
71
71
  add_child(_settings_tools)
72
72
 
73
- _filesystem_tools = FilesystemTools.new()
73
+ _filesystem_tools = GdhFilesystemTools.new()
74
74
  _filesystem_tools.name = "FilesystemTools"
75
75
  add_child(_filesystem_tools)
76
76
 
77
- _profile_tools = ProfileTools.new()
77
+ _profile_tools = GdhProfileTools.new()
78
78
  _profile_tools.name = "ProfileTools"
79
79
  add_child(_profile_tools)
80
80
 
@@ -4,19 +4,19 @@ extends Node
4
4
  ## Animations and animation trees, edited in the open editor or, for a project no editor serves, by a
5
5
  ## headless engine.
6
6
 
7
- const AnimationReads = preload("../animation_reads.gd")
8
- const HeadlessCheck = preload("../headless_check.gd")
9
- const PropertyValues = preload("../property_values.gd")
10
- const Read = preload("../reading.gd")
11
- const SceneFile = preload("../scene_file.gd")
12
- const Serialisation = preload("../serialisation.gd")
7
+ const GdhAnimationReads = preload("../animation_reads.gd")
8
+ const GdhHeadlessCheck = preload("../headless_check.gd")
9
+ const GdhPropertyValues = preload("../property_values.gd")
10
+ const GdhRead = preload("../reading.gd")
11
+ const GdhSceneFile = preload("../scene_file.gd")
12
+ const GdhSerialisation = preload("../serialisation.gd")
13
13
 
14
14
  ## How far right of the rightmost state a new one goes in the editor's graph, wider than a state's
15
15
  ## box there.
16
16
  const STATE_SPACING: float = 200.0
17
17
 
18
18
  var _editor_plugin: EditorPlugin = null
19
- var _properties: PropertyValues = PropertyValues.new()
19
+ var _properties: GdhPropertyValues = GdhPropertyValues.new()
20
20
 
21
21
 
22
22
  func set_editor_plugin(plugin: EditorPlugin) -> void:
@@ -42,15 +42,13 @@ func _find_node(root: Node, path: String) -> Node:
42
42
  ## [param kind] the scene owns. Answers [scene, node, refusal]; the refusal is {} when both were
43
43
  ## found.
44
44
  func _open_at(scene_path: String, node_path: String, kind: String) -> Array:
45
- var scene: SceneFile = SceneFile.new()
45
+ var scene: GdhSceneFile = GdhSceneFile.new()
46
46
  var refused: Dictionary = scene.open(scene_path, true)
47
47
  if not refused.is_empty():
48
48
  return [scene, null, refused]
49
49
  var node: Node = _find_node(scene.root, node_path)
50
50
  if node == null or not node.is_class(kind):
51
- return [
52
- scene, null, scene.refuse(scene.not_found("%s not found at: %s" % [kind, node_path], node_path))
53
- ]
51
+ return [scene, null, _not_of_kind(scene, node, node_path, kind)]
54
52
  var foreign: String = scene.foreign(node)
55
53
  if not foreign.is_empty():
56
54
  return [scene, null, scene.refuse(foreign)]
@@ -60,21 +58,34 @@ func _open_at(scene_path: String, node_path: String, kind: String) -> Array:
60
58
  ## [param scene_path] opened for reading, as [method _open_at] answers. A node an instanced scene
61
59
  ## owns is read like any other, since nothing is written.
62
60
  func _read_at(scene_path: String, node_path: String, kind: String) -> Array:
63
- var scene: SceneFile = SceneFile.new()
61
+ var scene: GdhSceneFile = GdhSceneFile.new()
64
62
  var refused: Dictionary = scene.open(scene_path, false)
65
63
  if not refused.is_empty():
66
64
  return [scene, null, refused]
67
65
  var node: Node = _find_node(scene.root, node_path)
68
66
  if node == null or not node.is_class(kind):
69
- return [
70
- scene, null, scene.refuse(scene.not_found("%s not found at: %s" % [kind, node_path], node_path))
71
- ]
67
+ return [scene, null, _not_of_kind(scene, node, node_path, kind)]
72
68
  return [scene, node, {}]
73
69
 
74
70
 
71
+ ## The refusal for [param node_path] in [param scene], where [param node] is what the scene has
72
+ ## there, null or not a [param kind], with where the scene's nodes of that kind are.
73
+ func _not_of_kind(scene: GdhSceneFile, node: Node, node_path: String, kind: String) -> Dictionary:
74
+ var said: String = "%s not found at: %s" % [kind, node_path]
75
+ if node == null:
76
+ said = scene.not_found(said, node_path)
77
+ var held: PackedStringArray = []
78
+ if scene.root.is_class(kind):
79
+ var _root_held: bool = held.append(".")
80
+ for found: Node in scene.root.find_children("*", kind, true, false):
81
+ var _held: bool = held.append(str(scene.root.get_path_to(found)))
82
+ var there: String = "" if node == null else node.get_class()
83
+ return scene.refuse(GdhRead.not_of_kind(said, node_path, there, kind, held))
84
+
85
+
75
86
  ## Writes [param scene] once [param check] passes, then the files of [param homes], answering
76
87
  ## [param answer] or a refusal.
77
- func _finish(scene: SceneFile, check: Callable, homes: Dictionary, answer: Dictionary) -> Dictionary:
88
+ func _finish(scene: GdhSceneFile, check: Callable, homes: Dictionary, answer: Dictionary) -> Dictionary:
78
89
  if not Engine.is_editor_hint():
79
90
  for file: Variant in homes:
80
91
  var home: Resource = homes[file]
@@ -91,7 +102,7 @@ func _finish(scene: SceneFile, check: Callable, homes: Dictionary, answer: Dicti
91
102
  )
92
103
  % file
93
104
  )
94
- + HeadlessCheck.REMEDY
105
+ + GdhHeadlessCheck.REMEDY
95
106
  )
96
107
  )
97
108
  )
@@ -100,7 +111,7 @@ func _finish(scene: SceneFile, check: Callable, homes: Dictionary, answer: Dicti
100
111
  return written
101
112
  for file: Variant in homes:
102
113
  var resource: Resource = homes[file]
103
- var saving: Error = SceneFile.save_keeping_uid(resource, str(file))
114
+ var saving: Error = GdhSceneFile.save_keeping_uid(resource, str(file))
104
115
  if saving != OK:
105
116
  return {"ok": false, "error": "Failed to save %s: %s" % [file, error_string(saving)]}
106
117
  if Engine.is_editor_hint():
@@ -112,14 +123,14 @@ func _finish(scene: SceneFile, check: Callable, homes: Dictionary, answer: Dicti
112
123
  ## engine ran as it loaded the file.
113
124
  func _scripted(resource: Resource) -> bool:
114
125
  var script: Script = resource.get_script()
115
- return (script != null and not script.is_tool()) or HeadlessCheck.holds_scripted_embedded(resource, {})
126
+ return (script != null and not script.is_tool()) or GdhHeadlessCheck.holds_scripted_embedded(resource, {})
116
127
 
117
128
 
118
129
  func _parse_json_maybe(value: Variant) -> Variant:
119
130
  if typeof(value) != TYPE_STRING:
120
131
  return value
121
132
  var text: String = value
122
- var parsed: Variant = Read.json_or_null(text)
133
+ var parsed: Variant = GdhRead.json_or_null(text)
123
134
  if parsed == null and text != "null":
124
135
  return value
125
136
  return parsed
@@ -140,7 +151,7 @@ func _parse_method_args(raw_args: Array) -> Array:
140
151
  ## edited in memory while only the scene was saved, which refers to the file, so the edit was
141
152
  ## answered as made and was gone; it is saved too. One inside some other file (an imported model,
142
153
  ## the scene this one inherits from) is refused, since nothing written here would keep the edit.
143
- func _homes(scene: SceneFile, held: Array) -> Array:
154
+ func _homes(scene: GdhSceneFile, held: Array) -> Array:
144
155
  var homes: Dictionary = {}
145
156
  for entry: Array in held:
146
157
  var resource: Resource = entry[0]
@@ -195,10 +206,10 @@ func _library_of(player: AnimationPlayer, animation_name: String) -> AnimationLi
195
206
 
196
207
  ## The state machine at [param state_machine_path] in [param anim_tree], with the files it is kept
197
208
  ## in, as [machine, homes, why not].
198
- func _machine(scene: SceneFile, anim_tree: AnimationTree, state_machine_path: String) -> Array:
199
- var sm: AnimationNodeStateMachine = AnimationReads.state_machine(anim_tree, state_machine_path)
209
+ func _machine(scene: GdhSceneFile, anim_tree: AnimationTree, state_machine_path: String) -> Array:
210
+ var sm: AnimationNodeStateMachine = GdhAnimationReads.state_machine(anim_tree, state_machine_path)
200
211
  if not sm:
201
- return [null, {}, AnimationReads.no_machine(anim_tree, state_machine_path)]
212
+ return [null, {}, GdhAnimationReads.no_machine(anim_tree, state_machine_path)]
202
213
  var homes: Array = _homes(scene, [[sm, "state machine"]])
203
214
  if not homes[0]:
204
215
  return [null, {}, homes[1]]
@@ -226,18 +237,18 @@ func read_animations(args: Dictionary) -> Dictionary:
226
237
  return {"ok": false, "error": "Missing scenePath"}
227
238
 
228
239
  var opened: Array = _read_at(scene_path, player_node_path, "AnimationPlayer")
229
- var scene: SceneFile = opened[0]
240
+ var scene: GdhSceneFile = opened[0]
230
241
  if opened[1] == null:
231
242
  return opened[2]
232
243
  var player: AnimationPlayer = opened[1]
233
- return _read_in(scene, AnimationReads.animations(player, animation_name))
244
+ return _read_in(scene, GdhAnimationReads.animations(player, animation_name))
234
245
 
235
246
 
236
247
  ## [param answer] read from [param scene], with whether the editor holds the scene unsaved.
237
- func _read_in(scene: SceneFile, answer: Dictionary) -> Dictionary:
248
+ func _read_in(scene: GdhSceneFile, answer: Dictionary) -> Dictionary:
238
249
  if not answer.get("ok", false):
239
250
  return scene.refuse(str(answer.get("error", "")))
240
- answer["unsavedInEditor"] = SceneFile.unsaved(scene.path)
251
+ answer["unsavedInEditor"] = GdhSceneFile.unsaved(scene.path)
241
252
  scene.close()
242
253
  return answer
243
254
 
@@ -253,11 +264,11 @@ func read_animation_states(args: Dictionary) -> Dictionary:
253
264
  return {"ok": false, "error": "Missing animTreePath"}
254
265
 
255
266
  var opened: Array = _read_at(scene_path, anim_tree_path, "AnimationTree")
256
- var scene: SceneFile = opened[0]
267
+ var scene: GdhSceneFile = opened[0]
257
268
  if opened[1] == null:
258
269
  return opened[2]
259
270
  var anim_tree: AnimationTree = opened[1]
260
- return _read_in(scene, AnimationReads.states(anim_tree, state_machine_path))
271
+ return _read_in(scene, GdhAnimationReads.states(anim_tree, state_machine_path))
261
272
 
262
273
 
263
274
  # =============================================================================
@@ -280,7 +291,7 @@ func create_animation(args: Dictionary) -> Dictionary:
280
291
  return {"ok": false, "error": "Unsupported loopMode: " + loop_mode_name}
281
292
 
282
293
  var opened: Array = _open_at(scene_path, player_node_path, "AnimationPlayer")
283
- var scene: SceneFile = opened[0]
294
+ var scene: GdhSceneFile = opened[0]
284
295
  if opened[1] == null:
285
296
  return opened[2]
286
297
  var player: AnimationPlayer = opened[1]
@@ -295,9 +306,9 @@ func create_animation(args: Dictionary) -> Dictionary:
295
306
  return scene.refuse(str(homes[1]))
296
307
 
297
308
  var anim: Animation = Animation.new()
298
- anim.length = Read.as_float(args.get("length", 1.0), 1.0)
299
- anim.loop_mode = Read.as_int(loop_modes[loop_mode_name]) as Animation.LoopMode
300
- anim.step = Read.as_float(args.get("step", 0.1), 0.1)
309
+ anim.length = GdhRead.as_float(args.get("length", 1.0), 1.0)
310
+ anim.loop_mode = GdhRead.as_int(loop_modes[loop_mode_name]) as Animation.LoopMode
311
+ anim.step = GdhRead.as_float(args.get("step", 0.1), 0.1)
301
312
  var called: String = animation_name.get_slice("/", 1) if animation_name.contains("/") else animation_name
302
313
  var add_err: Error = anim_lib.add_animation(StringName(called), anim)
303
314
  if add_err != OK:
@@ -337,7 +348,7 @@ func add_animation_track(args: Dictionary) -> Dictionary:
337
348
  return {"ok": false, "error": keyed[1]}
338
349
 
339
350
  var opened: Array = _open_at(scene_path, player_node_path, "AnimationPlayer")
340
- var scene: SceneFile = opened[0]
351
+ var scene: GdhSceneFile = opened[0]
341
352
  if opened[1] == null:
342
353
  return opened[2]
343
354
  var player: AnimationPlayer = opened[1]
@@ -429,7 +440,7 @@ func _add_track(
429
440
 
430
441
  for index: int in keyframes.size():
431
442
  var keyframe: Dictionary = keyframes[index]
432
- if anim.track_insert_key(track_idx, Read.as_float(keyframe["time"]), keys[index]) < 0:
443
+ if anim.track_insert_key(track_idx, GdhRead.as_float(keyframe["time"]), keys[index]) < 0:
433
444
  return [-1, "Keyframe %d could not be inserted." % index, null]
434
445
  return [track_idx, "", method_found]
435
446
 
@@ -450,7 +461,7 @@ func _keyframes(track: Dictionary) -> Array:
450
461
  var time: Variant = keyframe.get("time")
451
462
  if not (time is float or time is int):
452
463
  return [false, "keyframes[%d] has no time." % index]
453
- var seconds: float = Read.as_float(time)
464
+ var seconds: float = GdhRead.as_float(time)
454
465
  if times.has(seconds):
455
466
  return [
456
467
  false, "keyframes[%d] and [%d] are both at %s seconds." % [times[seconds], index, seconds]
@@ -504,7 +515,7 @@ func add_animation_state(args: Dictionary) -> Dictionary:
504
515
  return {"ok": false, "error": "Missing " + str(required[1])}
505
516
 
506
517
  var opened: Array = _open_at(scene_path, anim_tree_path, "AnimationTree")
507
- var scene: SceneFile = opened[0]
518
+ var scene: GdhSceneFile = opened[0]
508
519
  if opened[1] == null:
509
520
  return opened[2]
510
521
  var anim_tree: AnimationTree = opened[1]
@@ -547,7 +558,7 @@ func add_animation_state(args: Dictionary) -> Dictionary:
547
558
  "animationName": animation_name,
548
559
  # False when the tree has no player to look the animation up in.
549
560
  "animationFound": player != null,
550
- "position": Serialisation.new().serialize_value(position),
561
+ "position": GdhSerialisation.new().serialize_value(position),
551
562
  }
552
563
  var files: Dictionary = machine[1]
553
564
  return _finish(scene, Callable(), files, answer)
@@ -580,13 +591,13 @@ func connect_animation_states(args: Dictionary) -> Dictionary:
580
591
  return {"ok": false, "error": "Unsupported transitionType: " + transition_type}
581
592
  var transition: AnimationNodeStateMachineTransition = AnimationNodeStateMachineTransition.new()
582
593
  transition.switch_mode = (
583
- Read.as_int(modes[transition_type]) as AnimationNodeStateMachineTransition.SwitchMode
594
+ GdhRead.as_int(modes[transition_type]) as AnimationNodeStateMachineTransition.SwitchMode
584
595
  )
585
596
  if not advance_condition.is_empty():
586
597
  transition.advance_condition = StringName(advance_condition)
587
598
 
588
599
  var opened: Array = _open_at(scene_path, anim_tree_path, "AnimationTree")
589
- var scene: SceneFile = opened[0]
600
+ var scene: GdhSceneFile = opened[0]
590
601
  if opened[1] == null:
591
602
  return opened[2]
592
603
  var anim_tree: AnimationTree = opened[1]
@@ -4,8 +4,8 @@ extends Node
4
4
  ## The editor's view of the files on disk: scans, the reimports asked for, where each stands, and
5
5
  ## files moved under it.
6
6
 
7
- const Read = preload("../reading.gd")
8
- const SceneFile = preload("../scene_file.gd")
7
+ const GdhRead = preload("../reading.gd")
8
+ const GdhSceneFile = preload("../scene_file.gd")
9
9
 
10
10
  var _editor_plugin: EditorPlugin = null
11
11
 
@@ -63,7 +63,7 @@ func rescan_filesystem(args: Dictionary) -> Dictionary:
63
63
  var started: bool = false
64
64
  var completed_before: int = _scans_completed
65
65
  var uids: Dictionary = {"reread": [], "duplicated": []}
66
- if not Read.as_bool(args.get("statusOnly", false)) and not busy:
66
+ if not GdhRead.as_bool(args.get("statusOnly", false)) and not busy:
67
67
  uids = _reread_changed_uids(filesystem)
68
68
  # Files the caller has just written, moved or deleted, read again one by one. The scan finds a
69
69
  # script that appeared and leaves the global class of one that has gone in the editor's list,
@@ -172,7 +172,7 @@ func scan_status(_args: Dictionary) -> Dictionary:
172
172
  "ok": true,
173
173
  "scanning": filesystem.is_scanning(),
174
174
  "importing": filesystem.is_importing(),
175
- "pending": SceneFile.scan_due,
175
+ "pending": GdhSceneFile.scan_due,
176
176
  "sinceScanFinishedMs":
177
177
  -1 if _scan_finished_at_msec < 0 else Time.get_ticks_msec() - _scan_finished_at_msec,
178
178
  "reimportsCompleted": _reimports_completed,
@@ -9,7 +9,7 @@ extends Node
9
9
  ## tools answer at all.
10
10
 
11
11
  ## What the display server calls itself when the engine was started with no display at all.
12
- const Read = preload("../reading.gd")
12
+ const GdhRead = preload("../reading.gd")
13
13
 
14
14
  const HEADLESS_DISPLAY: String = "headless"
15
15
  ## Where Godot keeps the port its own debugger listens on for a game it is playing. One setting
@@ -245,7 +245,7 @@ func playing_status(_args: Dictionary) -> Dictionary:
245
245
  # play, so the one from when this editor greeted the server is a number it has moved off.
246
246
  var settings: EditorSettings = EditorInterface.get_editor_settings()
247
247
  var debugger: int = (
248
- Read.as_int(settings.get_setting(DEBUGGER_SETTING))
248
+ GdhRead.as_int(settings.get_setting(DEBUGGER_SETTING))
249
249
  if settings != null and settings.has_setting(DEBUGGER_SETTING)
250
250
  else 0
251
251
  )