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
@@ -3,19 +3,19 @@ extends Node
3
3
 
4
4
  ## Scenes and their nodes, edited in the open editor and read back from what it holds.
5
5
 
6
- const FileReads = preload("../file_reads.gd")
7
- const Read = preload("../reading.gd")
8
- const Kin = preload("scene_kin.gd")
9
- const Paths = preload("scene_paths.gd")
10
- const Placing = preload("scene_placing.gd")
11
- const PropertyValues = preload("../property_values.gd")
12
- const ResourceTools = preload("resource_tools.gd")
13
- const SceneFile = preload("../scene_file.gd")
14
- const Serialisation = preload("../serialisation.gd")
6
+ const GdhFileReads = preload("../file_reads.gd")
7
+ const GdhRead = preload("../reading.gd")
8
+ const GdhKin = preload("scene_kin.gd")
9
+ const GdhPaths = preload("scene_paths.gd")
10
+ const GdhPlacing = preload("scene_placing.gd")
11
+ const GdhPropertyValues = preload("../property_values.gd")
12
+ const GdhResourceTools = preload("resource_tools.gd")
13
+ const GdhSceneFile = preload("../scene_file.gd")
14
+ const GdhSerialisation = preload("../serialisation.gd")
15
15
 
16
16
  var _editor_plugin: EditorPlugin = null
17
- var _values: Serialisation = Serialisation.new()
18
- var _properties: PropertyValues = PropertyValues.new()
17
+ var _values: GdhSerialisation = GdhSerialisation.new()
18
+ var _properties: GdhPropertyValues = GdhPropertyValues.new()
19
19
 
20
20
 
21
21
  func set_editor_plugin(plugin: EditorPlugin) -> void:
@@ -47,7 +47,7 @@ func _to_scene_res_path(project_path: String, scene_path: String) -> String:
47
47
 
48
48
  ## [param scene_path] opened for a tool, as [scene, refusal]: the refusal is {} when it opened.
49
49
  func _open(scene_path: String, for_writing: bool) -> Array:
50
- var scene: SceneFile = SceneFile.new()
50
+ var scene: GdhSceneFile = GdhSceneFile.new()
51
51
  return [scene, scene.open(scene_path, for_writing)]
52
52
 
53
53
 
@@ -60,23 +60,21 @@ func _find_node(root: Node, path: String) -> Node:
60
60
  ## Why the property or signal [param missing] could not be found on [param node], adding the one
61
61
  ## cause the name alone does not show: a script that does not compile leaves the editor holding a
62
62
  ## placeholder with no properties or signals at all, and the refusal named the property instead.
63
+ ## Such a script has no engine class beneath it. Compiling a copy of the source to find out failed on
64
+ ## every script with a class_name, since the copy hides the global class the original declares.
63
65
  func _missing_on(node: Node, missing: String) -> String:
64
66
  var script: Script = node.get_script()
65
- if script == null or not script.has_source_code():
66
- return missing
67
- var probe: GDScript = GDScript.new()
68
- probe.source_code = script.source_code
69
- if probe.reload() == OK:
67
+ if script == null or not str(script.get_instance_base_type()).is_empty():
70
68
  return missing
71
69
  return (
72
70
  "%s. Its script, %s, does not compile, so none of what it declares is known here."
73
- % [missing, script.resource_path]
71
+ % [missing.trim_suffix("."), script.resource_path]
74
72
  )
75
73
 
76
74
 
77
75
  ## Whether each of [param names] reads the same off [param saved] as off [param node], answering
78
76
  ## the first that does not, or "".
79
- func _kept(scene: SceneFile, saved: Node, node: Node, names: Array) -> String:
77
+ func _kept(scene: GdhSceneFile, saved: Node, node: Node, names: Array) -> String:
80
78
  var at: String = scene.path_of(node)
81
79
  var copy: Node = saved.get_node_or_null(at)
82
80
  if copy == null:
@@ -106,7 +104,7 @@ func _properties_of(node: Node, include_defaults: bool, set_here: Dictionary) ->
106
104
  scripted[str(declared.get("name", ""))] = true
107
105
  var props: Dictionary = {}
108
106
  for p: Dictionary in node.get_property_list():
109
- if not (Read.as_int(p.get("usage", 0)) & PROPERTY_USAGE_STORAGE):
107
+ if not (GdhRead.as_int(p.get("usage", 0)) & PROPERTY_USAGE_STORAGE):
110
108
  continue
111
109
  var property: String = str(p.get("name", ""))
112
110
  if property.is_empty():
@@ -118,7 +116,7 @@ func _properties_of(node: Node, include_defaults: bool, set_here: Dictionary) ->
118
116
  if scripted.has(property)
119
117
  else ClassDB.class_get_property_default_value(node.get_class(), property)
120
118
  )
121
- if PropertyValues.same(value, default):
119
+ if GdhPropertyValues.same(value, default):
122
120
  continue
123
121
  props[property] = _readable(node, value)
124
122
  return props
@@ -141,7 +139,7 @@ func _parse_properties_arg(raw_properties: Variant) -> Dictionary:
141
139
  var text: String = str(raw_properties)
142
140
  if text.strip_edges().is_empty():
143
141
  return {}
144
- var parsed: Variant = Read.json_or_null(text)
142
+ var parsed: Variant = GdhRead.json_or_null(text)
145
143
  if typeof(parsed) == TYPE_DICTIONARY:
146
144
  return parsed
147
145
  return {}
@@ -157,7 +155,7 @@ func _collect_nodes_recursive(node: Node, path: String, out_nodes: Array) -> voi
157
155
  func _inherited(args: Dictionary) -> Dictionary:
158
156
  var project_path: String = str(args.get("projectPath", ""))
159
157
  var script_path: String = str(args.get("script", ""))
160
- return Kin.inherited(
158
+ return GdhKin.inherited(
161
159
  args,
162
160
  _new_scene_path(args),
163
161
  _to_scene_res_path(project_path, str(args.get("inherits", ""))),
@@ -191,7 +189,7 @@ func _create_of_a_class(args: Dictionary) -> Dictionary:
191
189
  if scene_path.is_empty():
192
190
  return {"ok": false, "error": "Missing scenePath"}
193
191
  var asked_type: String = root_node_type
194
- var made: Dictionary = SceneFile.made_as(
192
+ var made: Dictionary = GdhSceneFile.made_as(
195
193
  root_node_type,
196
194
  "" if script_path.is_empty() else _to_scene_res_path(project_path, script_path),
197
195
  "Node",
@@ -209,15 +207,15 @@ func _create_of_a_class(args: Dictionary) -> Dictionary:
209
207
  }
210
208
  if not ClassDB.can_instantiate(root_node_type):
211
209
  return {"ok": false, "error": "%s cannot be instantiated." % root_node_type}
212
- var unfit: String = SceneFile.unfit_name(root_node_name)
210
+ var unfit: String = GdhSceneFile.unfit_name(root_node_name)
213
211
  if not unfit.is_empty():
214
212
  return {"ok": false, "error": unfit}
215
213
  if FileAccess.file_exists(scene_path):
216
- return Kin.taken(scene_path)
214
+ return GdhKin.taken(scene_path)
217
215
 
218
216
  var root: Node = ClassDB.instantiate(root_node_type)
219
217
  root.name = root_node_name
220
- var scene: SceneFile = SceneFile.new()
218
+ var scene: GdhSceneFile = GdhSceneFile.new()
221
219
  scene.root = root
222
220
  scene.path = scene_path
223
221
  scene.asked(root, ["script"])
@@ -228,7 +226,7 @@ func _create_of_a_class(args: Dictionary) -> Dictionary:
228
226
  if script == null:
229
227
  root.free()
230
228
  return {"ok": false, "error": "No script loads from " + full_script_path}
231
- var uncompiled: String = SceneFile.uncompiled(script, full_script_path)
229
+ var uncompiled: String = GdhSceneFile.uncompiled(script, full_script_path)
232
230
  if not uncompiled.is_empty():
233
231
  root.free()
234
232
  return {"ok": false, "error": uncompiled}
@@ -245,7 +243,7 @@ func _create_of_a_class(args: Dictionary) -> Dictionary:
245
243
  # name is no property the write compares.
246
244
  root.name = root_node_name
247
245
 
248
- var folder: String = SceneFile.make_folder_for(scene_path)
246
+ var folder: String = GdhSceneFile.make_folder_for(scene_path)
249
247
  if not folder.is_empty():
250
248
  root.free()
251
249
  return {"ok": false, "error": folder}
@@ -259,14 +257,14 @@ func _create_of_a_class(args: Dictionary) -> Dictionary:
259
257
  func list_scene_nodes(args: Dictionary) -> Dictionary:
260
258
  var project_path: String = str(args.get("projectPath", ""))
261
259
  var scene_path: String = _to_scene_res_path(project_path, str(args.get("scenePath", "")))
262
- var depth: int = Read.as_int(args.get("depth", -1), -1)
263
- var include_properties: bool = Read.as_bool(args.get("includeProperties", false))
260
+ var depth: int = GdhRead.as_int(args.get("depth", -1), -1)
261
+ var include_properties: bool = GdhRead.as_bool(args.get("includeProperties", false))
264
262
 
265
263
  # Read as a headless engine reads it with no editor connected, so the answer does not depend on
266
264
  # whether one is.
267
- var read: Dictionary = FileReads.scene_tree(scene_path, depth, include_properties)
265
+ var read: Dictionary = GdhFileReads.scene_tree(scene_path, depth, include_properties)
268
266
  if read.get("ok", false):
269
- read["unsavedInEditor"] = SceneFile.unsaved(scene_path)
267
+ read["unsavedInEditor"] = GdhSceneFile.unsaved(scene_path)
270
268
  return read
271
269
 
272
270
 
@@ -284,20 +282,20 @@ func add_node(args: Dictionary) -> Dictionary:
284
282
  var asked_type: String = node_type
285
283
  var class_script: Script = null
286
284
  if not node_type.is_empty() and not ClassDB.class_exists(node_type):
287
- var declared: Dictionary = SceneFile.script_class(node_type, "Node")
285
+ var declared: Dictionary = GdhSceneFile.script_class(node_type, "Node")
288
286
  if declared.has("error"):
289
287
  return {"ok": false, "error": declared["error"]}
290
288
  var held: Variant = declared.get("script")
291
289
  if held is Script:
292
290
  class_script = held
293
291
  node_type = str(declared["base"])
294
- var making: Array = Placing.what_to_add(node_type, instance_path, scene_path)
292
+ var making: Array = GdhPlacing.what_to_add(node_type, instance_path, scene_path)
295
293
  var packed: PackedScene = making[0]
296
294
  if not str(making[1]).is_empty():
297
295
  return {"ok": false, "error": making[1]}
298
296
 
299
297
  var opened: Array = _open(scene_path, true)
300
- var scene: SceneFile = opened[0]
298
+ var scene: GdhSceneFile = opened[0]
301
299
  var refused: Dictionary = opened[1]
302
300
  if not refused.is_empty():
303
301
  return refused
@@ -313,19 +311,19 @@ func add_node(args: Dictionary) -> Dictionary:
313
311
  if not unusable.is_empty():
314
312
  return scene.refuse(unusable)
315
313
  var place: Variant = args.get("index")
316
- var unplaceable: String = Placing.unplaceable(parent, null, place)
314
+ var unplaceable: String = GdhPlacing.unplaceable(parent, null, place)
317
315
  if not unplaceable.is_empty():
318
316
  return scene.refuse(unplaceable)
319
317
 
320
318
  # In the tree before its properties, so a property holding a node can find it by path.
321
- var new_node: Node = Placing.made(packed, node_type)
319
+ var new_node: Node = GdhPlacing.made(packed, node_type)
322
320
  if class_script != null:
323
321
  scene.asked(new_node, ["script"])
324
322
  new_node.set_script(class_script)
325
323
  new_node.name = node_name
326
324
  parent.add_child(new_node)
327
- Placing.place(new_node, place)
328
- Placing.own(new_node, root)
325
+ GdhPlacing.place(new_node, place)
326
+ GdhPlacing.own(new_node, root)
329
327
  var unsettled: String = scene.settle()
330
328
  if not unsettled.is_empty():
331
329
  return scene.refuse("Nothing was written: " + unsettled)
@@ -343,6 +341,7 @@ func add_node(args: Dictionary) -> Dictionary:
343
341
  "nodePath": new_path,
344
342
  "index": new_node.get_index(),
345
343
  }
344
+ _properties.note_write(answer, new_node)
346
345
  var written: Dictionary = scene.write(
347
346
  func(saved: Node) -> String:
348
347
  return _kept(
@@ -373,7 +372,7 @@ func delete_node(args: Dictionary) -> Dictionary:
373
372
  }
374
373
 
375
374
  var opened: Array = _open(scene_path, true)
376
- var scene: SceneFile = opened[0]
375
+ var scene: GdhSceneFile = opened[0]
377
376
  var refused: Dictionary = opened[1]
378
377
  if not refused.is_empty():
379
378
  return refused
@@ -388,7 +387,7 @@ func delete_node(args: Dictionary) -> Dictionary:
388
387
  var at: String = scene.path_of(node)
389
388
  node.get_parent().remove_child(node)
390
389
  node.free()
391
- var carried: Paths = Paths.new()
390
+ var carried: GdhPaths = GdhPaths.new()
392
391
  var _rewritten: int = carried.carry(scene, {at: ""})
393
392
 
394
393
  var written: Dictionary = scene.write(
@@ -401,7 +400,7 @@ func delete_node(args: Dictionary) -> Dictionary:
401
400
  return written
402
401
 
403
402
  var answer: Dictionary = {"ok": true, "deletedNodePath": at}
404
- answer.merge(Kin.follow(scene_path, at, "", carried))
403
+ answer.merge(GdhKin.follow(scene_path, at, "", carried))
405
404
  return answer
406
405
 
407
406
 
@@ -416,7 +415,7 @@ func duplicate_node(args: Dictionary) -> Dictionary:
416
415
  return {"ok": false, "error": "Missing nodePath or newName"}
417
416
 
418
417
  var opened: Array = _open(scene_path, true)
419
- var scene: SceneFile = opened[0]
418
+ var scene: GdhSceneFile = opened[0]
420
419
  var refused: Dictionary = opened[1]
421
420
  if not refused.is_empty():
422
421
  return refused
@@ -444,14 +443,14 @@ func duplicate_node(args: Dictionary) -> Dictionary:
444
443
  return scene.refuse(unusable)
445
444
 
446
445
  var copies: Dictionary = {}
447
- var duplicated_node: Node = Placing.copied(source, root, copies)
446
+ var duplicated_node: Node = GdhPlacing.copied(source, root, copies)
448
447
  if not duplicated_node:
449
448
  return scene.refuse("Failed to duplicate node: " + node_path)
450
449
 
451
450
  duplicated_node.name = new_name
452
451
  target_parent.add_child(duplicated_node)
453
- Placing.own(duplicated_node, root)
454
- Placing.reconnect(copies, source)
452
+ GdhPlacing.own(duplicated_node, root)
453
+ GdhPlacing.reconnect(copies, source)
455
454
  scene.copied(copies)
456
455
 
457
456
  var new_path: String = scene.path_of(duplicated_node)
@@ -487,7 +486,7 @@ func reparent_node(args: Dictionary) -> Dictionary:
487
486
  return {"ok": false, "error": "Missing newParentPath"}
488
487
 
489
488
  var opened: Array = _open(scene_path, true)
490
- var scene: SceneFile = opened[0]
489
+ var scene: GdhSceneFile = opened[0]
491
490
  var refused: Dictionary = opened[1]
492
491
  if not refused.is_empty():
493
492
  return refused
@@ -515,7 +514,7 @@ func reparent_node(args: Dictionary) -> Dictionary:
515
514
  if not unusable.is_empty():
516
515
  return scene.refuse(unusable)
517
516
  var place: Variant = args.get("index")
518
- var unplaceable: String = Placing.unplaceable(new_parent, node, place)
517
+ var unplaceable: String = GdhPlacing.unplaceable(new_parent, node, place)
519
518
  if not unplaceable.is_empty():
520
519
  return scene.refuse(unplaceable)
521
520
 
@@ -525,12 +524,12 @@ func reparent_node(args: Dictionary) -> Dictionary:
525
524
  node.owner = null
526
525
  node.get_parent().remove_child(node)
527
526
  new_parent.add_child(node)
528
- Placing.place(node, place)
529
- Placing.own(node, root)
527
+ GdhPlacing.place(node, place)
528
+ GdhPlacing.own(node, root)
530
529
 
531
530
  var new_path: String = scene.path_of(node)
532
531
  var index: int = node.get_index()
533
- var carried: Paths = Paths.new()
532
+ var carried: GdhPaths = GdhPaths.new()
534
533
  var _rewritten: int = carried.carry(scene, {old_path: new_path} if new_path != old_path else {})
535
534
  var written: Dictionary = scene.write(
536
535
  func(saved: Node) -> String:
@@ -555,7 +554,7 @@ func reparent_node(args: Dictionary) -> Dictionary:
555
554
  "index": index,
556
555
  }
557
556
  if new_path != old_path:
558
- answer.merge(Kin.follow(scene_path, old_path, new_path, carried))
557
+ answer.merge(GdhKin.follow(scene_path, old_path, new_path, carried))
559
558
  return answer
560
559
 
561
560
 
@@ -569,7 +568,7 @@ func set_node_properties(args: Dictionary) -> Dictionary:
569
568
  return {"ok": false, "error": "set takes properties, editableChildren, or both."}
570
569
 
571
570
  var opened: Array = _open(scene_path, true)
572
- var scene: SceneFile = opened[0]
571
+ var scene: GdhSceneFile = opened[0]
573
572
  var refused: Dictionary = opened[1]
574
573
  if not refused.is_empty():
575
574
  return refused
@@ -590,10 +589,10 @@ func set_node_properties(args: Dictionary) -> Dictionary:
590
589
 
591
590
  var dropped: Dictionary = {}
592
591
  if editable != null:
593
- var not_an_instance: String = Kin.set_editable(scene, node, Read.as_bool(editable))
592
+ var not_an_instance: String = GdhKin.set_editable(scene, node, GdhRead.as_bool(editable))
594
593
  if not not_an_instance.is_empty():
595
594
  return scene.refuse(not_an_instance)
596
- if not Read.as_bool(editable):
595
+ if not GdhRead.as_bool(editable):
597
596
  dropped = scene.held_under(scene.path_of(node))
598
597
 
599
598
  var old_path: String = scene.path_of(node)
@@ -606,28 +605,31 @@ func set_node_properties(args: Dictionary) -> Dictionary:
606
605
  for key: Variant in properties:
607
606
  held[str(key)] = _readable(node, _properties.read_at(node, str(key)))
608
607
  var new_path: String = scene.path_of(node)
609
- var carried: Paths = Paths.new()
608
+ var answer: Dictionary = {"ok": true, "nodePath": new_path, "properties": held}
609
+ _properties.note_write(answer, node)
610
+ var carried: GdhPaths = GdhPaths.new()
610
611
  var _rewritten: int = carried.carry(scene, {old_path: new_path} if new_path != old_path else {})
611
612
  var written: Dictionary = scene.write(
612
613
  func(saved: Node) -> String:
613
614
  var unkept: String = _kept(scene, saved, node, properties.keys())
614
615
  if unkept.is_empty() and editable != null:
615
- if saved.is_editable_instance(saved.get_node(new_path)) != Read.as_bool(editable):
616
- return "%s would load with editableChildren %s." % [new_path, not Read.as_bool(editable)]
616
+ if saved.is_editable_instance(saved.get_node(new_path)) != GdhRead.as_bool(editable):
617
+ return (
618
+ "%s would load with editableChildren %s." % [new_path, not GdhRead.as_bool(editable)]
619
+ )
617
620
  return unkept
618
621
  )
619
622
  if not written.is_empty():
620
623
  carried.put_back(scene_path)
621
624
  return written
622
625
 
623
- var answer: Dictionary = {"ok": true, "nodePath": new_path, "properties": held}
624
626
  if editable != null:
625
- answer["editableChildren"] = Read.as_bool(editable)
627
+ answer["editableChildren"] = GdhRead.as_bool(editable)
626
628
  if not dropped.is_empty():
627
629
  answer["droppedValues"] = dropped["values"]
628
630
  answer["droppedNodes"] = dropped["nodes"]
629
631
  if new_path != old_path:
630
- answer.merge(Kin.follow(scene_path, old_path, new_path, carried))
632
+ answer.merge(GdhKin.follow(scene_path, old_path, new_path, carried))
631
633
  return answer
632
634
 
633
635
 
@@ -635,10 +637,10 @@ func get_node_properties(args: Dictionary) -> Dictionary:
635
637
  var project_path: String = str(args.get("projectPath", ""))
636
638
  var scene_path: String = _to_scene_res_path(project_path, str(args.get("scenePath", "")))
637
639
  var node_path: String = str(args.get("nodePath", "."))
638
- var include_defaults: bool = Read.as_bool(args.get("includeDefaults", false))
640
+ var include_defaults: bool = GdhRead.as_bool(args.get("includeDefaults", false))
639
641
 
640
642
  var opened: Array = _open(scene_path, false)
641
- var scene: SceneFile = opened[0]
643
+ var scene: GdhSceneFile = opened[0]
642
644
  var refused: Dictionary = opened[1]
643
645
  if not refused.is_empty():
644
646
  return refused
@@ -652,7 +654,7 @@ func get_node_properties(args: Dictionary) -> Dictionary:
652
654
  # variable read as changed; and a value this scene sets back to the default was hidden, so the
653
655
  # names this scene's file sets are always answered.
654
656
  var props: Dictionary = _properties_of(node, include_defaults, scene.set_here(node))
655
- var cells: Dictionary = ResourceTools.cells_of(node)
657
+ var cells: Dictionary = GdhResourceTools.cells_of(node)
656
658
  var answer: Dictionary = {"ok": true, "nodePath": node_path, "properties": props}
657
659
  if node != scene.root and node.owner != null and not node.scene_file_path.is_empty():
658
660
  answer["instanceOf"] = node.scene_file_path
@@ -660,7 +662,7 @@ func get_node_properties(args: Dictionary) -> Dictionary:
660
662
  scene.close()
661
663
  # Only an editor holds anything unsaved; a headless engine answering false would say it looked.
662
664
  if Engine.is_editor_hint():
663
- answer["unsavedInEditor"] = SceneFile.unsaved(scene_path)
665
+ answer["unsavedInEditor"] = GdhSceneFile.unsaved(scene_path)
664
666
  answer.merge(cells)
665
667
  # An empty answer read as a node with nothing on it, rather than one with nothing changed.
666
668
  if props.is_empty() and not include_defaults:
@@ -680,7 +682,7 @@ func save_scene(args: Dictionary) -> Dictionary:
680
682
  target_path = _to_scene_res_path(project_path, new_path_raw)
681
683
 
682
684
  if target_path != scene_path:
683
- var unsaved: String = SceneFile.unsaved_in_editor(target_path)
685
+ var unsaved: String = GdhSceneFile.unsaved_in_editor(target_path)
684
686
  if not unsaved.is_empty():
685
687
  return {"ok": false, "error": unsaved}
686
688
 
@@ -703,9 +705,9 @@ func save_scene(args: Dictionary) -> Dictionary:
703
705
  var packing: Error = packed.pack(open_root)
704
706
  if packing != OK:
705
707
  return {"ok": false, "error": "Failed to pack %s: %s" % [scene_path, error_string(packing)]}
706
- written = SceneFile.save_packed(packed, target_path)
708
+ written = GdhSceneFile.save_packed(packed, target_path)
707
709
  else:
708
- var scene: SceneFile = SceneFile.new()
710
+ var scene: GdhSceneFile = GdhSceneFile.new()
709
711
  var refused: Dictionary = scene.open(scene_path, true)
710
712
  if not refused.is_empty():
711
713
  return refused
@@ -743,7 +745,7 @@ func _save_open_scene(scene_path: String) -> Dictionary:
743
745
  "scenePath": scene_path,
744
746
  "savedPath": scene_path,
745
747
  "from": "editor",
746
- "unsavedInEditor": SceneFile.unsaved(scene_path)
748
+ "unsavedInEditor": GdhSceneFile.unsaved(scene_path)
747
749
  }
748
750
 
749
751
 
@@ -756,7 +758,7 @@ func connect_signal(args: Dictionary) -> Dictionary:
756
758
  var method_name: String = str(args.get("methodName", ""))
757
759
  # A connection without CONNECT_PERSIST is a runtime one, and PackedScene.pack drops those on
758
760
  # the way out: without this the scene saves unchanged and this answers success over nothing.
759
- var flags: int = Read.as_int(args.get("flags", 0)) | Object.CONNECT_PERSIST
761
+ var flags: int = GdhRead.as_int(args.get("flags", 0)) | Object.CONNECT_PERSIST
760
762
 
761
763
  if (
762
764
  source_node_path.is_empty()
@@ -767,7 +769,7 @@ func connect_signal(args: Dictionary) -> Dictionary:
767
769
  return {"ok": false, "error": "Missing required signal connection arguments"}
768
770
 
769
771
  var opened: Array = _open(scene_path, true)
770
- var scene: SceneFile = opened[0]
772
+ var scene: GdhSceneFile = opened[0]
771
773
  var refused: Dictionary = opened[1]
772
774
  if not refused.is_empty():
773
775
  return refused
@@ -785,7 +787,7 @@ func connect_signal(args: Dictionary) -> Dictionary:
785
787
  var flags_before: int = -1
786
788
  for connection: Dictionary in source.get_signal_connection_list(signal_name):
787
789
  if connection.get("callable") == callable:
788
- flags_before = Read.as_int(connection.get("flags", 0))
790
+ flags_before = GdhRead.as_int(connection.get("flags", 0))
789
791
  if source.is_connected(signal_name, callable):
790
792
  source.disconnect(signal_name, callable)
791
793
  var connect_result: Error = source.connect(signal_name, callable, flags)
@@ -812,7 +814,7 @@ func connect_signal(args: Dictionary) -> Dictionary:
812
814
  "targetNodePath": to,
813
815
  "methodName": method_name,
814
816
  "flags": saved_flags[0],
815
- "flagNames": SceneFile.flag_names(Read.as_int(saved_flags[0])),
817
+ "flagNames": GdhSceneFile.flag_names(GdhRead.as_int(saved_flags[0])),
816
818
  # Connected either way, as the editor's own dialog allows, since the method may be written
817
819
  # next; a caller told nothing learnt of a misspelt one only when the signal fired.
818
820
  "methodFound": method_found
@@ -822,14 +824,14 @@ func connect_signal(args: Dictionary) -> Dictionary:
822
824
  # looked like a lost write.
823
825
  if flags_before >= 0:
824
826
  answer["alreadyConnected"] = true
825
- if flags_before != Read.as_int(saved_flags[0]):
826
- answer["flagsBefore"] = SceneFile.flag_names(flags_before)
827
+ if flags_before != GdhRead.as_int(saved_flags[0]):
828
+ answer["flagsBefore"] = GdhSceneFile.flag_names(flags_before)
827
829
  return answer
828
830
 
829
831
 
830
832
  ## The two ends of a connection in [param scene], as [source, target], or [null, why not].
831
833
  func _connection_ends(
832
- scene: SceneFile, source_node_path: String, signal_name: String, target_node_path: String
834
+ scene: GdhSceneFile, source_node_path: String, signal_name: String, target_node_path: String
833
835
  ) -> Array:
834
836
  var source: Node = _find_node(scene.root, source_node_path)
835
837
  var target: Node = _find_node(scene.root, target_node_path)
@@ -844,7 +846,8 @@ func _connection_ends(
844
846
  if not foreign.is_empty():
845
847
  return [null, foreign]
846
848
  if not source.has_signal(signal_name):
847
- return [null, _missing_on(source, "%s has no signal %s" % [source_node_path, signal_name])]
849
+ var said: String = "%s has no signal %s" % [source_node_path, signal_name]
850
+ return [null, _missing_on(source, GdhRead.offered(said, signal_name, GdhRead.signals_of(source)))]
848
851
  return [source, target]
849
852
 
850
853
 
@@ -856,7 +859,7 @@ func _connection_flags(root: Node, from: String, signal_name: String, to: String
856
859
  if source == null or target == null or not source.has_signal(signal_name):
857
860
  return -1
858
861
  for conn: Dictionary in source.get_signal_connection_list(signal_name):
859
- var flags: int = Read.as_int(conn.get("flags", 0))
862
+ var flags: int = GdhRead.as_int(conn.get("flags", 0))
860
863
  var callable: Callable = conn.get("callable", Callable())
861
864
  if (
862
865
  flags & Object.CONNECT_PERSIST
@@ -884,7 +887,7 @@ func disconnect_signal(args: Dictionary) -> Dictionary:
884
887
  return {"ok": false, "error": "Missing required signal disconnection arguments"}
885
888
 
886
889
  var opened: Array = _open(scene_path, true)
887
- var scene: SceneFile = opened[0]
890
+ var scene: GdhSceneFile = opened[0]
888
891
  var refused: Dictionary = opened[1]
889
892
  if not refused.is_empty():
890
893
  return refused
@@ -916,6 +919,7 @@ func disconnect_signal(args: Dictionary) -> Dictionary:
916
919
 
917
920
  return {
918
921
  "ok": true,
922
+ "removed": true,
919
923
  "sourceNodePath": from,
920
924
  "signalName": signal_name,
921
925
  "targetNodePath": to,
@@ -929,7 +933,7 @@ func list_connections(args: Dictionary) -> Dictionary:
929
933
  var filter_path: String = str(args.get("nodePath", ""))
930
934
 
931
935
  var opened: Array = _open(scene_path, false)
932
- var scene: SceneFile = opened[0]
936
+ var scene: GdhSceneFile = opened[0]
933
937
  var refused: Dictionary = opened[1]
934
938
  if not refused.is_empty():
935
939
  return refused
@@ -955,7 +959,7 @@ func list_connections(args: Dictionary) -> Dictionary:
955
959
  if signal_name.is_empty():
956
960
  continue
957
961
  for conn: Dictionary in node.get_signal_connection_list(signal_name):
958
- var flags: int = Read.as_int(conn.get("flags", 0))
962
+ var flags: int = GdhRead.as_int(conn.get("flags", 0))
959
963
  if not flags & Object.CONNECT_PERSIST:
960
964
  continue
961
965
  var callable: Callable = conn.get("callable", Callable())
@@ -976,7 +980,7 @@ func list_connections(args: Dictionary) -> Dictionary:
976
980
  "targetNodePath": target_path,
977
981
  "methodName": str(callable.get_method()),
978
982
  "flags": flags,
979
- "flagNames": SceneFile.flag_names(flags),
983
+ "flagNames": GdhSceneFile.flag_names(flags),
980
984
  # False for a connection an instanced scene makes inside itself, which only that
981
985
  # scene can change.
982
986
  "editable": editable
@@ -987,5 +991,5 @@ func list_connections(args: Dictionary) -> Dictionary:
987
991
  scene.close()
988
992
  var listed: Dictionary = {"ok": true, "connections": connections}
989
993
  if Engine.is_editor_hint():
990
- listed["unsavedInEditor"] = SceneFile.unsaved(scene_path)
994
+ listed["unsavedInEditor"] = GdhSceneFile.unsaved(scene_path)
991
995
  return listed
@@ -14,10 +14,10 @@ extends Node
14
14
  ## question asked of two places: a value spelled differently here would read as the editor and the
15
15
  ## file disagreeing about something they agree about.
16
16
 
17
- const Read = preload("../reading.gd")
18
- const Serialisation = preload("../serialisation.gd")
17
+ const GdhRead = preload("../reading.gd")
18
+ const GdhSerialisation = preload("../serialisation.gd")
19
19
 
20
- var _values: Serialisation = Serialisation.new()
20
+ var _values: GdhSerialisation = GdhSerialisation.new()
21
21
 
22
22
 
23
23
  func get_project_setting(args: Dictionary) -> Dictionary:
@@ -47,7 +47,7 @@ func _settings_under(prefix: String) -> Dictionary:
47
47
  var setting: String = str(property.get("name", ""))
48
48
  if not setting.begins_with(prefix):
49
49
  continue
50
- var kind: int = Read.as_int(property.get("type", TYPE_NIL), TYPE_NIL)
50
+ var kind: int = GdhRead.as_int(property.get("type", TYPE_NIL), TYPE_NIL)
51
51
  var described: Dictionary = {
52
52
  "setting": setting,
53
53
  "type": type_string(kind),