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:
@@ -0,0 +1,111 @@
1
+ extends RefCounted
2
+
3
+ ## How each engine type built from fields is written: the fields it needs, the ones it reads when
4
+ ## they are there, and what a refusal says about a value that is not one.
5
+ ##
6
+ ## This file is the one beside the operations, and `bun run sync:gd` copies it into each addon.
7
+
8
+ # What each tag has to carry before it is built. A tag naming a type whose keys are not there is a
9
+ # tag somebody wrote by mistake or wrote for a different shape, and building one out of defaults
10
+ # answers with a Transform2D of zeros where the caller meant something else entirely. Unbuilt, it
11
+ # comes back as it arrived, and whoever asked can read it against the type they were expecting.
12
+ const REQUIRED: Dictionary = {
13
+ "Vector2": [["x", "y"]],
14
+ "Vector2i": [["x", "y"]],
15
+ "Vector3": [["x", "y", "z"]],
16
+ "Vector3i": [["x", "y", "z"]],
17
+ "Vector4": [["x", "y", "z", "w"]],
18
+ "Vector4i": [["x", "y", "z", "w"]],
19
+ "Rect2": [["position", "size"], ["x", "y", "width", "height"]],
20
+ "Rect2i": [["position", "size"], ["x", "y", "width", "height"]],
21
+ "Plane": [["normal", "d"]],
22
+ "Quaternion": [["x", "y", "z", "w"]],
23
+ "AABB": [["position", "size"]],
24
+ "Basis": [["x", "y", "z"]],
25
+ "Transform2D": [["x", "y", "origin"]],
26
+ "Transform3D": [["basis", "origin"]],
27
+ "Projection": [["x", "y", "z", "w"]],
28
+ "Color": [["r", "g", "b"]],
29
+ "NodePath": [["path"]],
30
+ "PackedByteArray": [["base64"]],
31
+ "float": [["value"]],
32
+ "int": [["value"]],
33
+ "RID": [["id"]],
34
+ "Dictionary": [["entries"]],
35
+ }
36
+ ## The fields a builder reads when they are there and does without when not.
37
+ const OPTIONAL: Dictionary = {
38
+ "Color": ["a"],
39
+ "PackedByteArray": ["size"],
40
+ }
41
+
42
+
43
+ ## How a value of [param type] is written to be read as one, for a refusal to name, or empty for a
44
+ ## type that is not built from fields. A refusal naming only the two types leaves a caller to find
45
+ ## the shape in the description of another op.
46
+ static func written_as(type: int) -> String:
47
+ var tag: String = type_string(type)
48
+ var alternatives: Array = REQUIRED.get(tag, [])
49
+ if alternatives.is_empty() or tag in ["float", "int", "Dictionary"]:
50
+ return ""
51
+ var keys: Array = alternatives[0]
52
+ var optional: Array = OPTIONAL.get(tag, [])
53
+ var parts: Array[String] = []
54
+ for key: Variant in keys + optional:
55
+ parts.append('"%s": ...' % key)
56
+ var shape: String = "{%s}" % ", ".join(parts)
57
+ if type == TYPE_COLOR:
58
+ return shape + ' or as its html code, "#ff8000"'
59
+ return shape
60
+
61
+
62
+ ## The keys of [param fields] that a [param tag] built from them would not read, one list for each
63
+ ## spelling of its fields carried whole. A rectangle has two: its corners, and four numbers.
64
+ ##
65
+ ## A builder drops a key it does not know without a word, so {"x": 1, "y": 2, "z": 3} for a Vector2
66
+ ## would be written as (1, 2) and answered as written: a value is built only when a list is empty.
67
+ static func spare(fields: Dictionary, tag: String) -> Array:
68
+ var optional: Array = OPTIONAL.get(tag, [])
69
+ var lists: Array = []
70
+ var alternatives: Array = REQUIRED.get(tag, [])
71
+ for alternative: Variant in alternatives:
72
+ var keys: Array = alternative
73
+ if keys.all(func(key: Variant) -> bool: return fields.has(key)):
74
+ var over: Callable = func(key: Variant) -> bool:
75
+ return str(key) != "_type" and not keys.has(key) and not optional.has(key)
76
+ lists.append(fields.keys().filter(over))
77
+ return lists
78
+
79
+
80
+ ## The sentences a refusal of [param value] where a [param type] goes ends with: which of its keys
81
+ ## kept it from being read as one, and how one is written. Empty for a type not built from fields.
82
+ ##
83
+ ## The refusal names only the two types, and the key is what the caller has to take out.
84
+ static func remedy(value: Variant, type: int) -> String:
85
+ var shape: String = written_as(type)
86
+ if shape.is_empty():
87
+ return ""
88
+ return _unread(value, type) + " A %s is sent as %s." % [type_string(type), shape]
89
+
90
+
91
+ static func _unread(value: Variant, type: int) -> String:
92
+ if not value is Dictionary:
93
+ return ""
94
+ var fields: Dictionary = value
95
+ var tag: String = type_string(type)
96
+ var lists: Array = spare(fields, tag)
97
+ var built: bool = lists.any(func(over: Array) -> bool: return over.is_empty())
98
+ if lists.is_empty() or built or str(fields.get("_type", tag)) != tag:
99
+ return ""
100
+ lists.sort_custom(func(a: Array, b: Array) -> bool: return a.size() < b.size())
101
+ var left: Array = lists[0]
102
+ var named: PackedStringArray = []
103
+ for key: Variant in left:
104
+ var _named: bool = named.append('"%s"' % key)
105
+ var fields_called: String = "field called" if named.size() == 1 else "fields called"
106
+ var note: String = (
107
+ " A %s has no %s %s, so the value is not read as one" % [tag, fields_called, " or ".join(named)]
108
+ )
109
+ if left.has("type") and not fields.has("_type"):
110
+ return note + ': a value names its type under "_type".'
111
+ return note + "."
@@ -0,0 +1 @@
1
+ uid://c1s610pw8xorl
@@ -4,9 +4,8 @@ extends RefCounted
4
4
  ## and by a headless engine with none connected from a bare node of the class given what the file
5
5
  ## stores, which runs no script of the scene's, so a read answers the same either way.
6
6
 
7
- const FileReads = preload("file_reads.gd")
8
- const Read = preload("reading.gd")
9
- const Serialisation = preload("serialisation.gd")
7
+ const GdhFileReads = preload("file_reads.gd")
8
+ const GdhSerialisation = preload("serialisation.gd")
10
9
 
11
10
  const LOOP_MODE_NAMES: Dictionary[int, String] = {
12
11
  Animation.LOOP_NONE: "none",
@@ -56,21 +55,10 @@ static func scene_states(scene_path: String, tree_path: String, state_machine_pa
56
55
  ## A node of the class the file gives the node at [param node_path], holding every property the
57
56
  ## files set but its script, as [node, null] or [null, refusal]. The caller frees it.
58
57
  static func _bare(scene_path: String, node_path: String, kind: String) -> Array:
59
- var read: Dictionary = FileReads.scene_node(scene_path, node_path)
60
- if not read.is_empty() and not read.get("ok", false):
58
+ var read: Dictionary = GdhFileReads.scene_node_of_kind(scene_path, node_path, kind)
59
+ if not read.get("ok", false):
61
60
  return [null, read]
62
- var type: String = str(read.get("type", ""))
63
- if not ClassDB.class_exists(type) or not ClassDB.is_parent_class(type, kind):
64
- var said: String = "%s not found at: %s" % [kind, node_path]
65
- if read.is_empty():
66
- var hinted: String = said
67
- if FileReads.scene_node(scene_path, node_path.get_slice("/", 0)).is_empty():
68
- hinted = Read.from_the_root(
69
- said, node_path, str(FileReads.scene_node(scene_path, ".").get("name", ""))
70
- )
71
- said = hinted if hinted != said else FileReads.missing_from(said, scene_path, node_path)
72
- return [null, {"ok": false, "error": said}]
73
- var bare: Node = ClassDB.instantiate(type)
61
+ var bare: Node = ClassDB.instantiate(str(read["type"]))
74
62
  bare.name = str(read["name"])
75
63
  var given: Dictionary = read["properties"]
76
64
  for property: Variant in given:
@@ -107,7 +95,7 @@ static func animations(player: AnimationPlayer, animation_name: String) -> Dicti
107
95
  answer["ok"] = true
108
96
  answer["animationName"] = animation_name
109
97
  var tracks: Array[Dictionary] = []
110
- var values: Serialisation = Serialisation.new()
98
+ var values: GdhSerialisation = GdhSerialisation.new()
111
99
  for track: int in anim.get_track_count():
112
100
  tracks.append(_track(anim, track, values))
113
101
  answer["tracks"] = tracks
@@ -122,7 +110,7 @@ static func _summary(anim: Animation) -> Dictionary:
122
110
  }
123
111
 
124
112
 
125
- static func _track(anim: Animation, track: int, values: Serialisation) -> Dictionary:
113
+ static func _track(anim: Animation, track: int, values: GdhSerialisation) -> Dictionary:
126
114
  var kind: int = anim.track_get_type(track)
127
115
  var path: NodePath = anim.track_get_path(track)
128
116
  var shaped: Dictionary = {
@@ -3,13 +3,13 @@ extends RefCounted
3
3
  # The bus layout is a project resource the engine loads at startup and this process holds in
4
4
  # memory, so every change is written back to that file or it is gone with the process.
5
5
 
6
- const Read = preload("reading.gd")
7
- const Log = preload("logger.gd")
6
+ const GdhRead = preload("reading.gd")
7
+ const GdhLog = preload("logger.gd")
8
8
 
9
- var _log: Log
9
+ var _log: GdhLog
10
10
 
11
11
 
12
- func _init(p_log: Log) -> void:
12
+ func _init(p_log: GdhLog) -> void:
13
13
  _log = p_log
14
14
 
15
15
 
@@ -17,7 +17,7 @@ func create_audio_bus(params: Dictionary) -> Dictionary:
17
17
  var bus_name: String = str(params.get("bus_name", ""))
18
18
  if bus_name.is_empty():
19
19
  return _log.failure("bus_name is required")
20
- var parent_idx: int = Read.as_int(params.get("parent_bus_index", 0))
20
+ var parent_idx: int = GdhRead.as_int(params.get("parent_bus_index", 0))
21
21
  if parent_idx < 0 or parent_idx >= AudioServer.bus_count:
22
22
  return _log.failure("No bus at index " + str(parent_idx))
23
23
  # Sends are by name, so a second bus with one would leave every send to it meaning either.
@@ -100,10 +100,10 @@ func get_audio_buses(_params: Dictionary) -> Dictionary:
100
100
 
101
101
 
102
102
  func set_audio_bus_effect(params: Dictionary) -> Dictionary:
103
- var bus_idx: int = Read.as_int(params.get("bus_index", 0))
104
- var effect_idx: int = Read.as_int(params.get("effect_index", 0))
103
+ var bus_idx: int = GdhRead.as_int(params.get("bus_index", 0))
104
+ var effect_idx: int = GdhRead.as_int(params.get("effect_index", 0))
105
105
  var effect_type: String = str(params.get("effect_type", ""))
106
- var enabled: bool = Read.as_bool(params.get("enabled", true), true)
106
+ var enabled: bool = GdhRead.as_bool(params.get("enabled", true), true)
107
107
  if bus_idx < 0 or bus_idx >= AudioServer.bus_count:
108
108
  return _log.failure("No bus at index " + str(bus_idx))
109
109
 
@@ -150,8 +150,8 @@ func set_audio_bus_effect(params: Dictionary) -> Dictionary:
150
150
 
151
151
 
152
152
  func set_audio_bus_volume(params: Dictionary) -> Dictionary:
153
- var bus_idx: int = Read.as_int(params.get("bus_index", 0))
154
- var volume_db: float = Read.as_float(params.get("volume_db", 0.0))
153
+ var bus_idx: int = GdhRead.as_int(params.get("bus_index", 0))
154
+ var volume_db: float = GdhRead.as_float(params.get("volume_db", 0.0))
155
155
  if bus_idx < 0 or bus_idx >= AudioServer.bus_count:
156
156
  return _log.failure("No bus at index " + str(bus_idx))
157
157
 
@@ -5,18 +5,18 @@ extends RefCounted
5
5
  # A game started from a stale editor then cannot resolve any class_name written since, and the
6
6
  # engine reads the same file headless, so the list is rebuilt here from the scripts themselves.
7
7
 
8
- const Patterns = preload("patterns.gd")
9
- const Read = preload("reading.gd")
10
- const FileWalk = preload("file_walk.gd")
11
- const Log = preload("logger.gd")
8
+ const GdhPatterns = preload("patterns.gd")
9
+ const GdhRead = preload("reading.gd")
10
+ const GdhFileWalk = preload("file_walk.gd")
11
+ const GdhLog = preload("logger.gd")
12
12
 
13
13
  const CACHE_PATH: String = "res://.godot/global_script_class_cache.cfg"
14
14
 
15
- var _log: Log
16
- var _files: FileWalk = FileWalk.new()
15
+ var _log: GdhLog
16
+ var _files: GdhFileWalk = GdhFileWalk.new()
17
17
 
18
18
 
19
- func _init(p_log: Log) -> void:
19
+ func _init(p_log: GdhLog) -> void:
20
20
  _log = p_log
21
21
 
22
22
 
@@ -102,8 +102,8 @@ func _entry_for(path: String, skipped: Array[Dictionary]) -> Dictionary:
102
102
  "base": StringName(str(base)),
103
103
  "class": StringName(declared),
104
104
  "icon": str(header.get("icon", "")),
105
- "is_abstract": Read.as_bool(header.get("abstract", false)),
106
- "is_tool": Read.as_bool(header.get("tool", false)),
105
+ "is_abstract": GdhRead.as_bool(header.get("abstract", false)),
106
+ "is_tool": GdhRead.as_bool(header.get("tool", false)),
107
107
  "language": StringName("GDScript"),
108
108
  "path": path,
109
109
  }
@@ -166,7 +166,7 @@ static func _extends_parts(text: String) -> Dictionary:
166
166
  path = rest.substr(1, closing - 1)
167
167
  rest = rest.substr(closing + 1)
168
168
  var names: Array[String] = []
169
- var name_at: RegEx = Patterns.compiled("^([A-Za-z_][A-Za-z0-9_]*)")
169
+ var name_at: RegEx = GdhPatterns.compiled("^([A-Za-z_][A-Za-z0-9_]*)")
170
170
  var dotted: bool = not path.is_empty()
171
171
  while true:
172
172
  if dotted:
@@ -195,8 +195,8 @@ static func _as_the_engine_opens(path: String) -> String:
195
195
  # previous, as {"found": true, "extends": the text after its keyword} with no "extends" for one that
196
196
  # extends nothing, or {} when one of them is not there.
197
197
  func _inner_class(lines: PackedStringArray, names: Array[String]) -> Dictionary:
198
- var class_line: RegEx = Patterns.compiled("^class\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*(.*)$")
199
- var inline_extends: RegEx = Patterns.compiled("^extends\\s+(.*)$")
198
+ var class_line: RegEx = GdhPatterns.compiled("^class\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*(.*)$")
199
+ var inline_extends: RegEx = GdhPatterns.compiled("^extends\\s+(.*)$")
200
200
  var start: int = 0
201
201
  var end: int = lines.size()
202
202
  var depth: int = 0
@@ -255,9 +255,9 @@ func _header_of(path: String) -> Dictionary:
255
255
  # which is where the body begins.
256
256
  func _header_in(lines: PackedStringArray) -> Dictionary:
257
257
  var header: Dictionary = {}
258
- var annotation: RegEx = Patterns.compiled('^@([a-z_]+)(?:\\(\\s*(?:"([^"]*)")?[^)]*\\))?\\s*')
259
- var extends_line: RegEx = Patterns.compiled("^extends\\s+(.*)$")
260
- var same_line: RegEx = Patterns.compiled("^\\s+extends\\s+(.*)$")
258
+ var annotation: RegEx = GdhPatterns.compiled('^@([a-z_]+)(?:\\(\\s*(?:"([^"]*)")?[^)]*\\))?\\s*')
259
+ var extends_line: RegEx = GdhPatterns.compiled("^extends\\s+(.*)$")
260
+ var same_line: RegEx = GdhPatterns.compiled("^\\s+extends\\s+(.*)$")
261
261
  for line: String in lines:
262
262
  var rest: String = line.strip_edges()
263
263
  # Annotations may share a line with what they annotate, as in `@abstract class_name X`.
@@ -275,7 +275,7 @@ func _header_in(lines: PackedStringArray) -> Dictionary:
275
275
  if rest.is_empty() or rest.begins_with("#"):
276
276
  continue
277
277
  if rest.begins_with("class_name"):
278
- var declared: RegExMatch = Patterns.declared_class(rest)
278
+ var declared: RegExMatch = GdhPatterns.declared_class(rest)
279
279
  if declared != null:
280
280
  header["class_name"] = declared.get_string(1)
281
281
  var after: RegExMatch = same_line.search(rest.substr(declared.get_end(1)))
@@ -1,8 +1,8 @@
1
1
  extends RefCounted
2
2
 
3
- const Read = preload("reading.gd")
4
- const Log = preload("logger.gd")
5
- const Serialisation = preload("serialisation.gd")
3
+ const GdhRead = preload("reading.gd")
4
+ const GdhLog = preload("logger.gd")
5
+ const GdhSerialisation = preload("serialisation.gd")
6
6
 
7
7
  # The base classes each category name stands for. Kept to the list the tool's schema offers, which
8
8
  # a case holds: the schema offered physics3d and ui, which this refused, and physics answered the 3D
@@ -33,11 +33,11 @@ const METHOD_FLAG_NAMES: Dictionary[int, String] = {
33
33
  METHOD_FLAG_VIRTUAL_REQUIRED: "virtual_required",
34
34
  }
35
35
 
36
- var _log: Log
37
- var _values: Serialisation = Serialisation.new()
36
+ var _log: GdhLog
37
+ var _values: GdhSerialisation = GdhSerialisation.new()
38
38
 
39
39
 
40
- func _init(p_log: Log) -> void:
40
+ func _init(p_log: GdhLog) -> void:
41
41
  _log = p_log
42
42
 
43
43
 
@@ -53,7 +53,7 @@ static func _under_any(name: String, bases: Array) -> bool:
53
53
  func query_classes(params: Dictionary) -> Dictionary:
54
54
  var filter: String = str(params.get("filter", ""))
55
55
  var category: String = str(params.get("category", ""))
56
- var instantiable_only: bool = Read.as_bool(params.get("instantiable_only", false))
56
+ var instantiable_only: bool = GdhRead.as_bool(params.get("instantiable_only", false))
57
57
 
58
58
  _log.info(
59
59
  (
@@ -107,7 +107,7 @@ func query_classes(params: Dictionary) -> Dictionary:
107
107
  # Query detailed info about a specific class from ClassDB
108
108
  func query_class_info(params: Dictionary) -> Dictionary:
109
109
  var class_name_str: String = str(params.get("class_name", ""))
110
- var include_inherited: bool = Read.as_bool(params.get("include_inherited", false))
110
+ var include_inherited: bool = GdhRead.as_bool(params.get("include_inherited", false))
111
111
 
112
112
  _log.info(
113
113
  "Querying class info for: " + class_name_str + " (include_inherited: " + str(include_inherited) + ")"
@@ -344,7 +344,7 @@ func _methods_of(class_name_str: String, include_inherited: bool) -> Array[Dicti
344
344
  "class_name": return_info.get("class_name", "")
345
345
  },
346
346
  "flags": m.get("flags", 0),
347
- "flag_names": _flag_names(Read.as_int(m.get("flags", 0))),
347
+ "flag_names": _flag_names(GdhRead.as_int(m.get("flags", 0))),
348
348
  # As values, tagged the way every other answer tags one: JSON writes a Vector2i it is
349
349
  # handed as its text, so TileMapLayer.set_cell's default atlas coords read "(-1, -1)".
350
350
  "default_args": _values.serialize_value(m.get("default_args", []))
@@ -370,12 +370,12 @@ static func _flag_names(flags: int) -> Array[String]:
370
370
  # Nil is a value that can be anything when the usage says so, and [param nil_name] otherwise: void
371
371
  # for what a method returns, and Variant for an argument or property with no type.
372
372
  static func _type_name(info: Dictionary, nil_name: String) -> String:
373
- var type: int = Read.as_int(info.get("type", 0))
373
+ var type: int = GdhRead.as_int(info.get("type", 0))
374
374
  var named: String = str(info.get("class_name", ""))
375
375
  if type == TYPE_OBJECT and not named.is_empty():
376
376
  return named
377
377
  if type == TYPE_NIL:
378
- return "Variant" if Read.as_int(info.get("usage", 0)) & PROPERTY_USAGE_NIL_IS_VARIANT else nil_name
378
+ return "Variant" if GdhRead.as_int(info.get("usage", 0)) & PROPERTY_USAGE_NIL_IS_VARIANT else nil_name
379
379
  return type_string(type)
380
380
 
381
381
 
@@ -384,7 +384,7 @@ func _properties_of(class_name_str: String, include_inherited: bool) -> Array[Di
384
384
 
385
385
  for p: Dictionary in ClassDB.class_get_property_list(class_name_str, not include_inherited):
386
386
  # A category, group or subgroup is an editor heading rather than a property.
387
- var usage: int = Read.as_int(p.get("usage", 0))
387
+ var usage: int = GdhRead.as_int(p.get("usage", 0))
388
388
  if usage & PROPERTY_USAGE_CATEGORY or usage & PROPERTY_USAGE_GROUP or usage & PROPERTY_USAGE_SUBGROUP:
389
389
  continue
390
390
  properties.append(