gdharness 1.3.0 → 1.3.2

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 (72) hide show
  1. package/build/cli.js +322 -96
  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/declared_values.gd +116 -0
  5. package/build/godot/addons/gdharness_editor/declared_values.gd.uid +1 -0
  6. package/build/godot/addons/gdharness_editor/file_reads.gd +65 -25
  7. package/build/godot/addons/gdharness_editor/headless_check.gd +7 -7
  8. package/build/godot/addons/gdharness_editor/plugin.gd +6 -6
  9. package/build/godot/addons/gdharness_editor/property_values.gd +222 -59
  10. package/build/godot/addons/gdharness_editor/reading.gd +65 -0
  11. package/build/godot/addons/gdharness_editor/scene_file.gd +28 -23
  12. package/build/godot/addons/gdharness_editor/serialisation.gd +49 -94
  13. package/build/godot/addons/gdharness_editor/tool_executor.gd +24 -24
  14. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +52 -41
  15. package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +4 -4
  16. package/build/godot/addons/gdharness_editor/tools/play_tools.gd +2 -2
  17. package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +14 -14
  18. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +175 -74
  19. package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +17 -17
  20. package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +14 -12
  21. package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +7 -7
  22. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +88 -84
  23. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +4 -4
  24. package/build/godot/addons/gdharness_editor/value_shapes.gd +118 -0
  25. package/build/godot/addons/gdharness_editor/value_shapes.gd.uid +1 -0
  26. package/build/godot/addons/gdharness_runtime/reading.gd +65 -0
  27. package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +18 -18
  28. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +29 -29
  29. package/build/godot/addons/gdharness_runtime/runtime_capture.gd +21 -18
  30. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +86 -80
  31. package/build/godot/addons/gdharness_runtime/runtime_input.gd +65 -64
  32. package/build/godot/addons/gdharness_runtime/runtime_items.gd +6 -6
  33. package/build/godot/addons/gdharness_runtime/runtime_menus.gd +8 -8
  34. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +6 -6
  35. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +10 -10
  36. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +7 -7
  37. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +41 -41
  38. package/build/godot/addons/gdharness_runtime/runtime_says.gd +3 -3
  39. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +33 -33
  40. package/build/godot/addons/gdharness_runtime/runtime_typing.gd +20 -20
  41. package/build/godot/addons/gdharness_runtime/runtime_values.gd +52 -25
  42. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +56 -50
  43. package/build/godot/addons/gdharness_runtime/serialisation.gd +49 -94
  44. package/build/godot/addons/gdharness_runtime/value_shapes.gd +118 -0
  45. package/build/godot/addons/gdharness_runtime/value_shapes.gd.uid +1 -0
  46. package/build/godot/operations/animation_reads.gd +7 -19
  47. package/build/godot/operations/audio_buses.gd +10 -10
  48. package/build/godot/operations/class_cache.gd +16 -16
  49. package/build/godot/operations/classdb_queries.gd +25 -15
  50. package/build/godot/operations/declared_values.gd +116 -0
  51. package/build/godot/operations/dependencies.gd +141 -33
  52. package/build/godot/operations/editor_tools.gd +12 -12
  53. package/build/godot/operations/export_presets.gd +14 -14
  54. package/build/godot/operations/file_reads.gd +65 -25
  55. package/build/godot/operations/file_walk.gd +34 -0
  56. package/build/godot/operations/gdscript_analysis.gd +27 -22
  57. package/build/godot/operations/gdscript_authoring.gd +122 -17
  58. package/build/godot/operations/godot_operations.gd +66 -63
  59. package/build/godot/operations/import_pipeline.gd +59 -20
  60. package/build/godot/operations/input_actions.gd +90 -18
  61. package/build/godot/operations/logger.gd +1 -1
  62. package/build/godot/operations/plugins.gd +8 -8
  63. package/build/godot/operations/project_config.gd +83 -20
  64. package/build/godot/operations/project_diagnostics.gd +36 -11
  65. package/build/godot/operations/property_values.gd +222 -59
  66. package/build/godot/operations/reading.gd +65 -0
  67. package/build/godot/operations/rename_checks.gd +3 -3
  68. package/build/godot/operations/resource_files.gd +9 -6
  69. package/build/godot/operations/script_check.gd +23 -7
  70. package/build/godot/operations/serialisation.gd +49 -94
  71. package/build/godot/operations/value_shapes.gd +118 -0
  72. package/package.json +1 -1
@@ -8,8 +8,9 @@ extends RefCounted
8
8
  ## only true of a running game: reaching a node by path, and fitting an argument to the type the
9
9
  ## method it is going to declares.
10
10
 
11
- const Read = preload("reading.gd")
12
- const Serialisation = preload("serialisation.gd")
11
+ const GdhRead = preload("reading.gd")
12
+ const GdhSerialisation = preload("serialisation.gd")
13
+ const GdhShapes = preload("value_shapes.gd")
13
14
 
14
15
  ## The engine singletons a call, a write or a read may name instead of a node: what the engine
15
16
  ## measures, and the engine settings that are the game's own. Not every singleton: OS runs programs
@@ -30,7 +31,7 @@ const SINGLETONS: Array[String] = [
30
31
  ## The most frames a press is held in one call, as many as a frames wait takes.
31
32
  const MOST_HELD: int = 600
32
33
 
33
- var _shared: Serialisation = Serialisation.new()
34
+ var _shared: GdhSerialisation = GdhSerialisation.new()
34
35
 
35
36
 
36
37
  ## Converts a Godot value into something JSON can carry.
@@ -70,10 +71,36 @@ static func node_at(root: Node, path: String) -> Dictionary:
70
71
 
71
72
  var node: Node = root.get_node_or_null(path)
72
73
  if node == null:
73
- return {"type": "error", "message": "Node not found: " + path}
74
+ return {"type": "error", "message": _not_found(root, path)}
74
75
  return {"node": node}
75
76
 
76
77
 
78
+ ## "Node not found" for [param path], with the deepest node of it the game has and the children that
79
+ ## node has instead, as a scene's refusal names them: a mistyped step was otherwise found by reading
80
+ ## the whole tree.
81
+ static func _not_found(root: Node, path: String) -> String:
82
+ var said: String = "Node not found: " + path
83
+ var parts: PackedStringArray = path.split("/", false)
84
+ var at: Node = root
85
+ var step: int = 0
86
+ if path.begins_with("/"):
87
+ if parts.is_empty() or parts[0] != str(root.name):
88
+ return said
89
+ step = 1
90
+ while step < parts.size():
91
+ var below: Node = at.get_node_or_null(NodePath(parts[step]))
92
+ if below == null:
93
+ break
94
+ at = below
95
+ step += 1
96
+ if step >= parts.size():
97
+ return said
98
+ var names: PackedStringArray = []
99
+ for child: Node in at.get_children():
100
+ var _named: bool = names.append(str(child.name))
101
+ return GdhRead.missing_below(said, "", PackedStringArray([str(at.get_path())]), parts[step], names)
102
+
103
+
77
104
  ## How many process frames a whole press holds before its release, from `holdFrames`: one unless
78
105
  ## asked, as the halves of a press have always been a frame apart. Held inside the game because the
79
106
  ## time between a press, a wait and a release sent as three calls counts as held too: a 60-frame
@@ -86,7 +113,7 @@ static func held_for(params: Dictionary) -> Variant:
86
113
  "holdFrames holds a whole press and then lets go, and pressed asks for one half of one:"
87
114
  + " give one or the other."
88
115
  )
89
- var frames: int = Read.as_int(params["holdFrames"], 0)
116
+ var frames: int = GdhRead.as_int(params["holdFrames"], 0)
90
117
  if frames < 1 or frames > MOST_HELD:
91
118
  return "holdFrames is %d, and it takes 1 to %d." % [frames, MOST_HELD]
92
119
  return frames
@@ -126,12 +153,12 @@ static func target_at(root: Node, path: String) -> Dictionary:
126
153
 
127
154
  ## Whether two values can be compared without the comparison itself failing.
128
155
  static func comparable(one: Variant, other: Variant) -> bool:
129
- return Serialisation.comparable(one, other)
156
+ return GdhSerialisation.comparable(one, other)
130
157
 
131
158
 
132
159
  ## Whether a value can be handed to a parameter declared as [param type] without the call failing.
133
160
  static func acceptable(value: Variant, type: int) -> bool:
134
- return Serialisation.acceptable(value, type)
161
+ return GdhSerialisation.acceptable(value, type)
135
162
 
136
163
 
137
164
  ## Whether [param given] would have to be cut to become a [param type]: a fraction made a whole
@@ -146,10 +173,10 @@ static func cuts(given: Variant, type: int) -> bool:
146
173
  var number: Variant = given
147
174
  if given is String:
148
175
  var text: String = given
149
- number = Read.json_or_null(text)
176
+ number = GdhRead.json_or_null(text)
150
177
  if typeof(number) != TYPE_FLOAT and typeof(number) != TYPE_INT:
151
178
  return false
152
- var value: float = Read.as_float(number)
179
+ var value: float = GdhRead.as_float(number)
153
180
  var whole: bool = value == floorf(value)
154
181
  if type == TYPE_INT:
155
182
  return not whole
@@ -161,14 +188,14 @@ static func cut_by(type: int) -> String:
161
188
  return "an int" if type == TYPE_INT else "a bool"
162
189
 
163
190
 
164
- ## Why [param given] may not be the whole number sent, or "": see [method Serialisation.inexact].
191
+ ## Why [param given] may not be the whole number sent, or "": see [method GdhSerialisation.inexact].
165
192
  static func inexact(given: Variant, type: int) -> String:
166
- return Serialisation.inexact(given, type)
193
+ return GdhSerialisation.inexact(given, type)
167
194
 
168
195
 
169
- ## How a value of [param type] is written to be read as one, or empty when it is not built from fields.
170
- static func written_as(type: int) -> String:
171
- return Serialisation.written_as(type)
196
+ ## What a refusal of [param value] where a [param type] goes ends with: see [method GdhShapes.remedy].
197
+ static func remedy(value: Variant, type: int) -> String:
198
+ return GdhShapes.remedy(value, type)
172
199
 
173
200
 
174
201
  ## The declared type of one parameter of a method, or TYPE_NIL when the method or the parameter
@@ -181,7 +208,7 @@ func parameter_type(object: Object, method: String, index: int) -> int:
181
208
  if index < 0 or index >= params.size():
182
209
  return TYPE_NIL
183
210
  var parameter: Dictionary = params[index]
184
- return Read.as_int(parameter.get("type", TYPE_NIL), TYPE_NIL)
211
+ return GdhRead.as_int(parameter.get("type", TYPE_NIL), TYPE_NIL)
185
212
  return TYPE_NIL
186
213
 
187
214
 
@@ -214,7 +241,7 @@ func parameter_class(object: Object, method: String, index: int) -> String:
214
241
  static func slot_declared(holder: Variant, named: String) -> Dictionary:
215
242
  # A component holds one kind of value and no other: a vector's axis is a number, its integer
216
243
  # form's an integer, a rectangle's size a vector of the same form.
217
- if named in Serialisation.components_of(holder):
244
+ if named in GdhSerialisation.components_of(holder):
218
245
  var component: Variant = holder[named]
219
246
  return {"type": typeof(component), "class": "", "script": null}
220
247
  if holder is Array:
@@ -238,7 +265,7 @@ static func slot_declared(holder: Variant, named: String) -> Dictionary:
238
265
  for entry: Dictionary in object.get_property_list():
239
266
  if str(entry.get("name", "")) == named:
240
267
  return {
241
- "type": Read.as_int(entry.get("type", TYPE_NIL), TYPE_NIL),
268
+ "type": GdhRead.as_int(entry.get("type", TYPE_NIL), TYPE_NIL),
242
269
  "class": str(entry.get("class_name", "")),
243
270
  "script": null,
244
271
  }
@@ -336,7 +363,7 @@ func parameter_container(object: Object, method: String, index: int) -> Variant:
336
363
  if index < 0 or index >= params.size():
337
364
  return null
338
365
  var parameter: Dictionary = params[index]
339
- var hint: int = Read.as_int(parameter.get("hint", 0), 0)
366
+ var hint: int = GdhRead.as_int(parameter.get("hint", 0), 0)
340
367
  var named: String = str(parameter.get("hint_string", ""))
341
368
  if hint == PROPERTY_HINT_ARRAY_TYPE:
342
369
  var element: Dictionary = _element_type(named)
@@ -414,7 +441,7 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
414
441
  built, template.get_typed_builtin(), template.get_typed_class_name(), template.get_typed_script()
415
442
  )
416
443
  if typed.size() != built.size():
417
- return {"message": "the engine would not take its elements as what the list holds"}
444
+ return {"message": "the engine would not take its elements as what the list holds."}
418
445
  return {"value": typed}
419
446
  if like is Dictionary and given is Dictionary:
420
447
  var map_like: Dictionary = like
@@ -452,13 +479,14 @@ func typed_like(given: Variant, like: Variant, resolve: Callable) -> Dictionary:
452
479
  map_like.get_typed_value_script()
453
480
  )
454
481
  if typed_map.size() != rebuilt.size():
455
- return {"message": "the engine would not take its entries as what the map holds"}
482
+ return {"message": "the engine would not take its entries as what the map holds."}
456
483
  return {"value": typed_map}
457
484
  return {"value": given}
458
485
 
459
486
 
460
487
  ## One element fitted to a container's element type, as `{"value"}` or `{"message"}` saying what it
461
- ## was and what goes there. The message is the part after "element N".
488
+ ## was and what goes there. The message is the part after "element N", whole sentences, since it
489
+ ## can end with how a value of that type is sent.
462
490
  ##
463
491
  ## An object element given as a record goes to [param resolve] as a path would, which says how an
464
492
  ## object is named, rather than being refused as a map that cannot become the class.
@@ -468,7 +496,7 @@ func _element(item: Variant, builtin: int, declared: String, script: Script, res
468
496
  if builtin == TYPE_OBJECT and (item is String or item is Dictionary):
469
497
  var named: Dictionary = resolve.call(item, declared, script)
470
498
  if named.has("message"):
471
- return {"message": str(named["message"])}
499
+ return {"message": str(named["message"]) + "."}
472
500
  return {"value": named["object"]}
473
501
  var fitted_item: Variant = fitted(item, builtin)
474
502
  if not acceptable(fitted_item, builtin):
@@ -477,7 +505,6 @@ func _element(item: Variant, builtin: int, declared: String, script: Script, res
477
505
  var wanted: String = type_string(builtin)
478
506
  if builtin == TYPE_OBJECT:
479
507
  wanted = declared if script == null else script_named(script)
480
- return {
481
- "message": "is %s, which cannot become %s" % [JSON.stringify(serialize(item), "", false), wanted]
482
- }
508
+ var sent: String = JSON.stringify(serialize(item), "", false)
509
+ return {"message": "is %s, which cannot become %s.%s" % [sent, wanted, remedy(item, builtin)]}
483
510
  return {"value": fitted_item}
@@ -3,12 +3,12 @@ extends RefCounted
3
3
  ## The commands that take time: they let the game run and answer when what was waited for has
4
4
  ## happened, or when the time ran out, so the caller never sleeps for a guessed length.
5
5
 
6
- const Changes = preload("runtime_changes.gd")
7
- const Paths = preload("runtime_paths.gd")
8
- const Queries = preload("runtime_queries.gd")
9
- const Read = preload("reading.gd")
10
- const Says = preload("runtime_says.gd")
11
- const Values = preload("runtime_values.gd")
6
+ const GdhChanges = preload("runtime_changes.gd")
7
+ const GdhPaths = preload("runtime_paths.gd")
8
+ const GdhQueries = preload("runtime_queries.gd")
9
+ const GdhRead = preload("reading.gd")
10
+ const GdhSays = preload("runtime_says.gd")
11
+ const GdhValues = preload("runtime_values.gd")
12
12
 
13
13
  ## The longest one wait may last, whatever the request says: past this the server has long
14
14
  ## since given up on the reply.
@@ -30,12 +30,12 @@ const COMPARES: Array[String] = ["==", "!=", ">=", "<=", ">", "<"]
30
30
  const MOST_WATCHES: int = 16
31
31
 
32
32
  var _host: Node
33
- var _values: Values
34
- var _watches: Dictionary[int, Watch] = {}
33
+ var _values: GdhValues
34
+ var _watches: Dictionary[int, GdhWatch] = {}
35
35
  var _next_watch: int = 1
36
36
 
37
37
 
38
- func _init(host: Node, values: Values) -> void:
38
+ func _init(host: Node, values: GdhValues) -> void:
39
39
  _host = host
40
40
  _values = values
41
41
 
@@ -52,7 +52,7 @@ static func _out_of_range(named: String, asked: int, least: int, most: int) -> D
52
52
 
53
53
 
54
54
  func wait_frames(params: Dictionary) -> Dictionary:
55
- var frames: int = Read.as_int(params.get("frames", 1), 1)
55
+ var frames: int = GdhRead.as_int(params.get("frames", 1), 1)
56
56
  if frames < 1 or frames > MOST_FRAMES:
57
57
  return _out_of_range("frames", frames, 1, MOST_FRAMES)
58
58
  var started: int = Time.get_ticks_msec()
@@ -66,22 +66,22 @@ func wait_frames(params: Dictionary) -> Dictionary:
66
66
  func wait_signal(params: Dictionary) -> Dictionary:
67
67
  var node_path: String = str(params.get("path", ""))
68
68
  var signal_name: String = str(params.get("signal", ""))
69
- var timeout_ms: int = Read.as_int(params.get("timeout_ms", 5000), 5000)
69
+ var timeout_ms: int = GdhRead.as_int(params.get("timeout_ms", 5000), 5000)
70
70
  if timeout_ms < 1 or timeout_ms > CEILING_MSEC:
71
71
  return _out_of_range("timeout_ms", timeout_ms, 1, CEILING_MSEC)
72
72
  if params.has("watch"):
73
- return await _collect(Read.as_int(params["watch"], 0), timeout_ms)
73
+ return await _collect(GdhRead.as_int(params["watch"], 0), timeout_ms)
74
74
  if node_path.is_empty() or signal_name.is_empty():
75
75
  return {"type": "error", "message": "Node path and signal name required"}
76
76
 
77
- var standing: Dictionary = Values.node_at(_host.get_tree().root, node_path)
77
+ var standing: Dictionary = GdhValues.node_at(_host.get_tree().root, node_path)
78
78
  if standing.has("message"):
79
79
  return standing
80
80
  var node: Node = standing["node"]
81
81
  if not node.has_signal(signal_name):
82
82
  return {"type": "error", "message": "%s has no signal %s" % [node_path, signal_name]}
83
83
 
84
- var catcher: SignalCatcher = SignalCatcher.new()
84
+ var catcher: GdhSignalCatcher = GdhSignalCatcher.new()
85
85
  var callable: Callable = catcher._on_fired
86
86
  var listening: Error = node.connect(signal_name, callable, CONNECT_ONE_SHOT)
87
87
  if listening != OK:
@@ -119,13 +119,13 @@ func watch_signal(params: Dictionary) -> Dictionary:
119
119
  var signal_name: String = str(params.get("signal", ""))
120
120
  if node_path.is_empty() or signal_name.is_empty():
121
121
  return {"type": "error", "message": "Node path and signal name required"}
122
- var standing: Dictionary = Values.node_at(_host.get_tree().root, node_path)
122
+ var standing: Dictionary = GdhValues.node_at(_host.get_tree().root, node_path)
123
123
  if standing.has("message"):
124
124
  return standing
125
125
  var node: Node = standing["node"]
126
126
  if not node.has_signal(signal_name):
127
127
  return {"type": "error", "message": "%s has no signal %s" % [node_path, signal_name]}
128
- var watch: Watch = Watch.new(node, node_path, signal_name)
128
+ var watch: GdhWatch = GdhWatch.new(node, node_path, signal_name)
129
129
  var listening: Error = node.connect(signal_name, watch.catcher._on_fired)
130
130
  if listening != OK:
131
131
  return {"type": "error", "message": "Could not listen to signal: " + signal_name}
@@ -153,7 +153,7 @@ func _collect(id: int, timeout_ms: int) -> Dictionary:
153
153
  % [id, MOST_WATCHES]
154
154
  ),
155
155
  }
156
- var watch: Watch = _watches[id]
156
+ var watch: GdhWatch = _watches[id]
157
157
  var started: int = Time.get_ticks_msec()
158
158
  var before: bool = watch.catcher.fired
159
159
  while not watch.catcher.fired and Time.get_ticks_msec() - started < timeout_ms:
@@ -175,7 +175,7 @@ func _collect(id: int, timeout_ms: int) -> Dictionary:
175
175
 
176
176
 
177
177
  func _let_go(id: int) -> void:
178
- var watch: Watch = _watches.get(id)
178
+ var watch: GdhWatch = _watches.get(id)
179
179
  var _gone: bool = _watches.erase(id)
180
180
  if watch == null:
181
181
  return
@@ -192,12 +192,12 @@ func wait_until(params: Dictionary) -> Dictionary:
192
192
  var node_path: String = str(params.get("path", ""))
193
193
  var property: String = str(params.get("property", ""))
194
194
  var says: String = str(params.get("says", ""))
195
- var timeout_ms: int = Read.as_int(params.get("timeout_ms", 5000), 5000)
195
+ var timeout_ms: int = GdhRead.as_int(params.get("timeout_ms", 5000), 5000)
196
196
  if timeout_ms < 1 or timeout_ms > CEILING_MSEC:
197
197
  return _out_of_range("timeout_ms", timeout_ms, 1, CEILING_MSEC)
198
198
  if node_path.is_empty():
199
199
  return {"type": "error", "message": "Node path required"}
200
- var standing: Dictionary = Values.node_at(_host.get_tree().root, node_path)
200
+ var standing: Dictionary = GdhValues.node_at(_host.get_tree().root, node_path)
201
201
  if standing.has("message"):
202
202
  return standing
203
203
  # Two different questions, not two ways of asking one: says looks for words anywhere under the
@@ -220,7 +220,7 @@ func wait_until(params: Dictionary) -> Dictionary:
220
220
  )
221
221
  }
222
222
  if not says.is_empty():
223
- var include_hidden: bool = Read.as_bool(params.get("include_hidden", false))
223
+ var include_hidden: bool = GdhRead.as_bool(params.get("include_hidden", false))
224
224
  return await _wait_until_said(node_path, says, timeout_ms, include_hidden)
225
225
  var unasked: String = _property_wait_unasked(property, params)
226
226
  if not unasked.is_empty():
@@ -250,12 +250,12 @@ func wait_until(params: Dictionary) -> Dictionary:
250
250
  # two ops would disagree about one property, and the wait would run out on the text null.
251
251
  var untyped_object: bool = declared == TYPE_NIL and (current == null or typeof(current) == TYPE_OBJECT)
252
252
  var holds_objects: bool = declared == TYPE_OBJECT or untyped_object
253
- if holds_objects and Changes.names_no_object(wanted):
253
+ if holds_objects and GdhChanges.names_no_object(wanted):
254
254
  wanted = null
255
255
  var refused: String = _not_comparable(current, wanted, node_path, property)
256
256
  if refused.is_empty():
257
257
  refused = _cut_to_fit(params["value"], typeof(current), node_path, property)
258
- var rounded: String = Values.inexact(params["value"], typeof(current))
258
+ var rounded: String = GdhValues.inexact(params["value"], typeof(current))
259
259
  if refused.is_empty() and not rounded.is_empty():
260
260
  refused = "%s.%s holds int: %s." % [node_path, property, rounded]
261
261
  var never_held: bool = typeof(wanted) != TYPE_NIL and typeof(wanted) != TYPE_OBJECT
@@ -279,8 +279,8 @@ func wait_until(params: Dictionary) -> Dictionary:
279
279
  # the wait ran out on a value the game had reached.
280
280
  var differs: bool = compare == "!="
281
281
  while (
282
- Values.comparable(current, wanted)
283
- and Changes.held_already(wanted, current) == differs
282
+ GdhValues.comparable(current, wanted)
283
+ and GdhChanges.held_already(wanted, current) == differs
284
284
  and Time.get_ticks_msec() - started < timeout_ms
285
285
  ):
286
286
  await _host.get_tree().process_frame
@@ -297,7 +297,7 @@ func wait_until(params: Dictionary) -> Dictionary:
297
297
  "path": node_path,
298
298
  "property": property,
299
299
  "compare": compare,
300
- "met": Values.comparable(current, wanted) and Changes.held_already(wanted, current) != differs,
300
+ "met": GdhValues.comparable(current, wanted) and GdhChanges.held_already(wanted, current) != differs,
301
301
  "value": _values.serialize(current),
302
302
  "elapsed_ms": Time.get_ticks_msec() - started,
303
303
  "frames": frames,
@@ -334,7 +334,7 @@ func _wait_in_order(node: Node, params: Dictionary, current: Variant, timeout_ms
334
334
  var number: Variant = given
335
335
  if given is String:
336
336
  var text: String = given
337
- number = Read.json_or_null(text)
337
+ number = GdhRead.json_or_null(text)
338
338
  if typeof(number) != TYPE_INT and typeof(number) != TYPE_FLOAT:
339
339
  return {
340
340
  "type": "error",
@@ -344,7 +344,7 @@ func _wait_in_order(node: Node, params: Dictionary, current: Variant, timeout_ms
344
344
  % [compare, str(given)]
345
345
  )
346
346
  }
347
- var limit: float = Read.as_float(number)
347
+ var limit: float = GdhRead.as_float(number)
348
348
 
349
349
  var started: int = Time.get_ticks_msec()
350
350
  var frames: int = 0
@@ -386,9 +386,9 @@ static func _no_order(current: Variant, node_path: String, property: String, com
386
386
  ## Whether [param current], a number, stands to [param limit] as [param compare] says. Level counts
387
387
  ## at the precision the property keeps, so a 32-bit float holding 0.30000001 is at least 0.3.
388
388
  static func _in_order(compare: String, limit: float, current: Variant) -> bool:
389
- var reading: float = Read.as_float(current)
389
+ var reading: float = GdhRead.as_float(current)
390
390
  var level: bool = (
391
- reading == limit or (typeof(current) == TYPE_FLOAT and Changes.held_already(limit, current))
391
+ reading == limit or (typeof(current) == TYPE_FLOAT and GdhChanges.held_already(limit, current))
392
392
  )
393
393
  match compare:
394
394
  ">=":
@@ -407,14 +407,14 @@ static func _in_order(compare: String, limit: float, current: Variant) -> bool:
407
407
  ## conversion truncates: 3.5 waited on an int became 3 and 0.2 on a bool became true, and a property
408
408
  ## already holding that answered met at once, about a state nobody asked for.
409
409
  static func _cut_to_fit(given: Variant, type: int, node_path: String, property: String) -> String:
410
- if not Values.cuts(given, type):
410
+ if not GdhValues.cuts(given, type):
411
411
  return ""
412
412
  return (
413
413
  (
414
414
  "%s.%s holds %s and the value to wait for is %s, which %s cannot hold without changing it:"
415
415
  + " waiting on it would answer about a state nobody asked for."
416
416
  )
417
- % [node_path, property, type_string(type), str(given), Values.cut_by(type)]
417
+ % [node_path, property, type_string(type), str(given), GdhValues.cut_by(type)]
418
418
  )
419
419
 
420
420
 
@@ -436,15 +436,18 @@ static func _not_comparable(current: Variant, wanted: Variant, node_path: String
436
436
  # A value that cannot become what the property holds is said as that, which names the remedy,
437
437
  # before the comparison it would also fail; an object on either side is said as the comparison.
438
438
  var objects: bool = typeof(current) == TYPE_OBJECT or typeof(wanted) == TYPE_OBJECT
439
- if not objects and not Values.acceptable(wanted, typeof(current)):
439
+ if not objects and not GdhValues.acceptable(wanted, typeof(current)):
440
440
  return (
441
441
  (
442
- "%s.%s holds %s and the value to wait for is %s, which cannot become one:"
443
- + " waiting on it would answer about a state nobody asked for."
442
+ (
443
+ "%s.%s holds %s and the value to wait for is %s, which cannot become one:"
444
+ + " waiting on it would answer about a state nobody asked for."
445
+ )
446
+ % types
444
447
  )
445
- % types
448
+ + GdhValues.remedy(wanted, typeof(current))
446
449
  )
447
- if not Values.comparable(current, wanted):
450
+ if not GdhValues.comparable(current, wanted):
448
451
  return (
449
452
  (
450
453
  "%s.%s holds %s and the value to wait for is %s. Those cannot be compared, and"
@@ -452,13 +455,16 @@ static func _not_comparable(current: Variant, wanted: Variant, node_path: String
452
455
  )
453
456
  % types
454
457
  )
455
- if not Values.acceptable(wanted, typeof(current)):
458
+ if not GdhValues.acceptable(wanted, typeof(current)):
456
459
  return (
457
460
  (
458
- "%s.%s holds %s and the value to wait for is %s, which cannot become one:"
459
- + " waiting on it would answer about a state nobody asked for."
461
+ (
462
+ "%s.%s holds %s and the value to wait for is %s, which cannot become one:"
463
+ + " waiting on it would answer about a state nobody asked for."
464
+ )
465
+ % types
460
466
  )
461
- % types
467
+ + GdhValues.remedy(wanted, typeof(current))
462
468
  )
463
469
  return ""
464
470
 
@@ -472,15 +478,15 @@ static func _not_comparable(current: Variant, wanted: Variant, node_path: String
472
478
  ## its nodes hold: a run object built afresh each day would leave a wait watching the day before. A
473
479
  ## step that has gone in the meantime ends the wait with what went.
474
480
  static func _watched(node: Node, node_path: String, property: String) -> Dictionary:
475
- var reached: Dictionary = Paths.walk_to(node, node_path, property)
481
+ var reached: Dictionary = GdhPaths.walk_to(node, node_path, property)
476
482
  if reached.has("message"):
477
483
  return reached
478
484
  var holder: Variant = reached["holder"]
479
485
  var named: String = reached["name"]
480
- var missing: String = Paths.nothing_under(holder, named, str(reached["called"]))
486
+ var missing: String = GdhPaths.nothing_under(holder, named, str(reached["called"]))
481
487
  if not missing.is_empty():
482
488
  return {"type": "error", "message": missing}
483
- return {"value": Paths.read_under(holder, named), "declared": _declared_type(holder, named)}
489
+ return {"value": GdhPaths.read_under(holder, named), "declared": _declared_type(holder, named)}
484
490
 
485
491
 
486
492
  ## The type [param named] is declared with on [param holder], read the way a set reads it, so the two
@@ -489,9 +495,9 @@ static func _watched(node: Node, node_path: String, property: String) -> Diction
489
495
  ## on it runs out the timeout while a set of 5 on it is refused at once. TYPE_NIL for anything
490
496
  ## declaring none, and for a call, whose answer nothing declares.
491
497
  static func _declared_type(holder: Variant, named: String) -> int:
492
- if not Paths.method_of(named).is_empty():
498
+ if not GdhPaths.method_of(named).is_empty():
493
499
  return TYPE_NIL
494
- return Values.slot_declared(holder, named)["type"]
500
+ return GdhValues.slot_declared(holder, named)["type"]
495
501
 
496
502
 
497
503
  ## Waits until something under [param node_path] has [param said] written on it.
@@ -574,7 +580,7 @@ func _anything_says(node_path: String, said: String, include_hidden: bool) -> bo
574
580
  var pending: Array[Node] = [root]
575
581
  while not pending.is_empty():
576
582
  var node: Node = pending.pop_back()
577
- if Says.says(node, said) and (include_hidden or Queries.shown(node)):
583
+ if GdhSays.says(node, said) and (include_hidden or GdhQueries.shown(node)):
578
584
  return true
579
585
  pending.append_array(node.get_children(true))
580
586
  return false
@@ -584,7 +590,7 @@ func _anything_says(node_path: String, said: String, include_hidden: bool) -> bo
584
590
  ## awaits the signal directly, so the wait can also give up. Takes any number of arguments: a
585
591
  ## handler of five fixed ones covered the engine's signals, and a game's own signal with six was
586
592
  ## never delivered to it, so the wait ran out and said the signal had not fired.
587
- class SignalCatcher:
593
+ class GdhSignalCatcher:
588
594
  extends RefCounted
589
595
  var fired: bool = false
590
596
  ## How many times it fired; [member args] holds what the first carried.
@@ -599,12 +605,12 @@ class SignalCatcher:
599
605
 
600
606
 
601
607
  ## A signal recorded from when it was armed until it is collected.
602
- class Watch:
608
+ class GdhWatch:
603
609
  extends RefCounted
604
610
  var node: WeakRef
605
611
  var node_path: String
606
612
  var signal_name: String
607
- var catcher: SignalCatcher = SignalCatcher.new()
613
+ var catcher: GdhSignalCatcher = GdhSignalCatcher.new()
608
614
 
609
615
  func _init(watched: Node, path: String, named: String) -> void:
610
616
  node = weakref(watched)