gdharness 1.3.9 → 1.3.10

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 (73) hide show
  1. package/build/cli.js +4563 -3195
  2. package/build/godot/addons/gdharness_editor/animation_reads.gd +115 -4
  3. package/build/godot/addons/gdharness_editor/declared_values.gd +272 -0
  4. package/build/godot/addons/gdharness_editor/file_reads.gd +102 -18
  5. package/build/godot/addons/gdharness_editor/headless_check.gd +49 -2
  6. package/build/godot/addons/gdharness_editor/property_paths.gd +89 -16
  7. package/build/godot/addons/gdharness_editor/property_values.gd +180 -121
  8. package/build/godot/addons/gdharness_editor/reading.gd +51 -1
  9. package/build/godot/addons/gdharness_editor/scene_file.gd +77 -140
  10. package/build/godot/addons/gdharness_editor/scene_uids.gd +107 -0
  11. package/build/godot/addons/gdharness_editor/scene_uids.gd.uid +1 -0
  12. package/build/godot/addons/gdharness_editor/serialisation.gd +11 -22
  13. package/build/godot/addons/gdharness_editor/setting_reads.gd +121 -0
  14. package/build/godot/addons/gdharness_editor/setting_reads.gd.uid +1 -0
  15. package/build/godot/addons/gdharness_editor/tool_executor.gd +28 -5
  16. package/build/godot/addons/gdharness_editor/tools/animation_states.gd +39 -20
  17. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +49 -362
  18. package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +464 -0
  19. package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd.uid +1 -0
  20. package/build/godot/addons/gdharness_editor/tools/class_tools.gd +37 -0
  21. package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +221 -0
  22. package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd.uid +1 -0
  23. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +147 -492
  24. package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -0
  25. package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +4 -3
  26. package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +2 -1
  27. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +79 -5
  28. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +7 -30
  29. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +183 -37
  30. package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +485 -0
  31. package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd.uid +1 -0
  32. package/build/godot/addons/gdharness_editor/value_shapes.gd +128 -1
  33. package/build/godot/addons/gdharness_runtime/declared_values.gd +272 -0
  34. package/build/godot/addons/gdharness_runtime/reading.gd +51 -1
  35. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +35 -3
  36. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +185 -30
  37. package/build/godot/addons/gdharness_runtime/runtime_input.gd +86 -79
  38. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +17 -0
  39. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +13 -4
  40. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +309 -22
  41. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +163 -20
  42. package/build/godot/addons/gdharness_runtime/runtime_screen.gd +49 -3
  43. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +5 -2
  44. package/build/godot/addons/gdharness_runtime/runtime_values.gd +146 -5
  45. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +279 -11
  46. package/build/godot/addons/gdharness_runtime/runtime_words.gd +27 -0
  47. package/build/godot/addons/gdharness_runtime/serialisation.gd +11 -22
  48. package/build/godot/addons/gdharness_runtime/value_shapes.gd +128 -1
  49. package/build/godot/operations/animation_reads.gd +115 -4
  50. package/build/godot/operations/audio_buses.gd +93 -7
  51. package/build/godot/operations/classdb_queries.gd +119 -7
  52. package/build/godot/operations/declared_values.gd +272 -0
  53. package/build/godot/operations/dependencies.gd +154 -41
  54. package/build/godot/operations/editor_tools.gd +22 -14
  55. package/build/godot/operations/export_presets.gd +602 -4
  56. package/build/godot/operations/file_reads.gd +102 -18
  57. package/build/godot/operations/gdscript_authoring.gd +11 -1
  58. package/build/godot/operations/godot_operations.gd +16 -2
  59. package/build/godot/operations/import_pipeline.gd +20 -221
  60. package/build/godot/operations/input_actions.gd +108 -47
  61. package/build/godot/operations/project_config.gd +83 -69
  62. package/build/godot/operations/project_diagnostics.gd +4 -0
  63. package/build/godot/operations/project_validation.gd +266 -0
  64. package/build/godot/operations/property_paths.gd +89 -16
  65. package/build/godot/operations/property_values.gd +180 -121
  66. package/build/godot/operations/reading.gd +51 -1
  67. package/build/godot/operations/scene_connections.gd +222 -0
  68. package/build/godot/operations/serialisation.gd +11 -22
  69. package/build/godot/operations/setting_reads.gd +121 -0
  70. package/build/godot/operations/value_shapes.gd +128 -1
  71. package/build/godot/tests/listed.gd +20 -13
  72. package/build/keeper.js +1371 -706
  73. package/package.json +1 -1
@@ -68,6 +68,18 @@ static func through_script(object: Object, names: Dictionary) -> bool:
68
68
  return false
69
69
 
70
70
 
71
+ ## Whether [param object] still holds [param held] for [param name] once set to [param wanted]
72
+ ## because the engine derives it, as it keeps layout_mode at Container under a container: an engine
73
+ ## property, so no script code ran for the set, and an editor saves the same.
74
+ static func kept_by_engine(object: Object, name: String, wanted: Variant, held: Variant) -> bool:
75
+ return (
76
+ not GdhSame.same(object.get(name), wanted)
77
+ and GdhSame.same(object.get(name), held)
78
+ and name != "script"
79
+ and not through_script(object, {name: true})
80
+ )
81
+
82
+
71
83
  ## The stored properties of [param object] that are not in [param names] and no longer hold what
72
84
  ## [param before] recorded. One the object did not have before, which a script set on it declares,
73
85
  ## counts once it holds anything but its default; one it no longer has went with the old script.
@@ -366,8 +378,14 @@ static func embedded_changes(before: String, after: String, reached_ids: Diction
366
378
  ## Compares the file just saved at [param path] with [param before], what it held, and puts back
367
379
  ## what a script that is not a tool changed in it: in its embedded resources, which [param values]
368
380
  ## reach, and in [param main], its main resource, unless that is null. [param asked] and
369
- ## [param reached_ids] are what the call changed. Saved again through [param resave], which answers
370
- ## an Error, and answers "" or why the file still does not hold what it should.
381
+ ## [param reached_ids] are what the call changed, and [param carried] is [method embedded_in] of
382
+ ## [param values] taken before the save. Saved again through [param resave], which answers an Error,
383
+ ## and answers "" or why the file still does not hold what it should.
384
+ ##
385
+ ## An id is compared only where the resource holding it after the save held it before. Each headless
386
+ ## engine hands out the ids of one sequence, so a resource the call added can be saved under the id
387
+ ## the file had kept for one it dropped. Read as one resource, the new third line of a dialogue was
388
+ ## taken for the old first one changed by its script, and given the old one's text back.
371
389
  static func settle_saved(
372
390
  path: String,
373
391
  before: String,
@@ -375,6 +393,7 @@ static func settle_saved(
375
393
  main: Object,
376
394
  asked: Dictionary,
377
395
  reached_ids: Dictionary,
396
+ carried: Dictionary,
378
397
  resave: Callable
379
398
  ) -> String:
380
399
  for attempt: int in 2:
@@ -383,6 +402,8 @@ static func settle_saved(
383
402
  var embedded: Array[Array] = []
384
403
  for found: Array in embedded_changes(before, after, reached_ids):
385
404
  var holder: Resource = by_id.get(found[0])
405
+ if not carried.has(found[0]) or (holder != null and not is_same(holder, carried[found[0]])):
406
+ continue
386
407
  if holder != null and _unchanged(holder, found.slice(1)):
387
408
  continue
388
409
  if found[2] or holder == null or not at_default(holder, str(found[1])):
@@ -458,6 +479,32 @@ static func put_back_value(object: Object, name: String, was_set: bool, held: St
458
479
  return ""
459
480
 
460
481
 
482
+ ## [param refused], a refusal of [param property] on [param object] for not holding what it was given,
483
+ ## with why when a headless engine set it through a script that is not a tool. That setter runs here
484
+ ## and in the game, and an editor runs none and saves the value given, so a setter clamping stock to
485
+ ## 0 refused -5 here and the same call through an editor wrote it.
486
+ static func setter_ran(object: Object, property: String, refused: String) -> String:
487
+ if Engine.is_editor_hint() or property.is_empty():
488
+ return refused
489
+ if not through_script(object, {property.get_slice(":", 0): true}):
490
+ return refused
491
+ var attached: Variant = object.get_script()
492
+ var named: String = "Its script"
493
+ if attached is Script:
494
+ var script: Script = attached
495
+ named = script.resource_path
496
+ return (
497
+ (
498
+ (
499
+ "%s %s is not a tool script, so its setter ran in the headless engine writing this as it runs "
500
+ + "in the game; an editor runs none and would have saved the value given. "
501
+ )
502
+ % [refused, named]
503
+ )
504
+ + REMEDY
505
+ )
506
+
507
+
461
508
  ## Why [param name] on [param what] cannot be saved as the file held it.
462
509
  static func unasked(what: String, name: String, why: String = "") -> String:
463
510
  return (
@@ -26,38 +26,109 @@ static func declared_on(target: Object, property: String) -> Dictionary:
26
26
  ## start with the name of one holding a resource built into it, then a slash and a key of that
27
27
  ## resource: "sources/0/0:0/0/probability" is the probability of tile 0:0 in the atlas source a
28
28
  ## TileSet keeps as sources/0. A colon path cannot reach it, since the tile's own name holds colons.
29
- ## A resource kept in a file of its own is not reached, nor, given the file [param home] that
30
- ## [param target] is saved in, one built into another file, since writing it here would leave that
31
- ## file as it was.
29
+ ## A list of resources is stepped into by an element's index: "lines/1/text" is the text of the
30
+ ## second resource in lines. A resource kept in a file of its own is not reached, nor, given the
31
+ ## file [param home] that [param target] is saved in, one built into another file, since writing it
32
+ ## here would leave that file as it was.
32
33
  static func holder_of(target: Object, key: String, home: String = "") -> Array:
33
34
  var through: Array[Resource] = []
34
35
  var holder: Object = target
35
36
  var name: String = key
36
37
  while declared_on(holder, name).is_empty():
37
38
  var reached: Resource = null
39
+ var rest: int = -1
38
40
  var at: int = name.find("/")
39
41
  while at > 0:
40
- var held: Resource = built_in_at(holder, name.left(at), home)
41
- if held != null:
42
+ var stepped: Array = _stepped(holder, name, at)
43
+ var held: Resource = stepped[0]
44
+ if held != null and _built_into(held, home):
42
45
  reached = held
46
+ rest = GdhRead.as_int(stepped[1])
43
47
  break
44
48
  at = name.find("/", at + 1)
45
49
  if reached == null:
46
50
  break
47
51
  through.append(reached)
48
52
  holder = reached
49
- name = name.substr(at + 1)
53
+ name = name.substr(rest)
50
54
  return [holder, name, through]
51
55
 
52
56
 
53
- ## The resource [param target] holds under [param property] when it is built into a file, or null;
54
- ## given [param home], only one built into that file or into none yet.
55
- static func built_in_at(target: Object, property: String, home: String = "") -> Resource:
56
- var held: Resource = held_at(target, property)
57
- if held == null or not held.is_built_in():
58
- return null
57
+ ## The resource the part of [param name] before the slash at [param at] reaches on [param target],
58
+ ## as [resource, where the rest of [param name] starts], or [null, -1]: the one held under that key,
59
+ ## or the element of the list held there that the step after the slash indexes.
60
+ static func _stepped(target: Object, name: String, at: int) -> Array:
61
+ var head: String = name.left(at)
62
+ var held: Resource = held_at(target, head)
63
+ if held != null:
64
+ return [held, at + 1]
65
+ var end: int = name.find("/", at + 1)
66
+ if end < 0 or declared_on(target, head).is_empty():
67
+ return [null, -1]
68
+ var index: String = name.substr(at + 1, end - at - 1)
69
+ var listed: Variant = target.get(head)
70
+ if not listed is Array or not index.is_valid_int():
71
+ return [null, -1]
72
+ var items: Array = listed
73
+ var place: int = index.to_int()
74
+ if place < 0 or place >= items.size() or not items[place] is Resource:
75
+ return [null, -1]
76
+ return [items[place], end + 1]
77
+
78
+
79
+ ## The refusal for [param name], which [param target] does not declare, when a step of it indexes a
80
+ ## list [param target] holds and names no resource in it; or "".
81
+ static func unlisted(target: Object, name: String) -> String:
82
+ var at: int = name.find("/")
83
+ while at > 0:
84
+ var head: String = name.left(at)
85
+ var listed: Variant = null if declared_on(target, head).is_empty() else target.get(head)
86
+ if listed is Array:
87
+ var items: Array = listed
88
+ return _unlisted_in(items, "%s.%s" % [class_called(target), head], name, at)
89
+ at = name.find("/", at + 1)
90
+ return ""
91
+
92
+
93
+ static func _unlisted_in(items: Array, called: String, name: String, at: int) -> String:
94
+ var head: String = name.left(at)
95
+ var end: int = name.find("/", at + 1)
96
+ var index: String = name.substr(at + 1) if end < 0 else name.substr(at + 1, end - at - 1)
97
+ if items.is_empty():
98
+ return "%s holds no elements, so %s names none: give %s a whole list first." % [called, name, head]
99
+ var last: int = items.size() - 1
100
+ if not index.is_valid_int():
101
+ return (
102
+ "%s is a list, so the step after it is the index of one of its elements, from 0 to %d, not %s."
103
+ % [called, last, index]
104
+ )
105
+ var place: int = index.to_int()
106
+ if place < 0 or place > last:
107
+ return (
108
+ "%s holds %d element%s, so %s names none: an index goes from 0 to %d."
109
+ % [called, items.size(), "" if items.size() == 1 else "s", name, last]
110
+ )
111
+ if not items[place] is Resource:
112
+ return (
113
+ "%s/%d holds %s, which has no properties to write: give %s a whole list instead."
114
+ % [head, place, type_string(typeof(items[place])), head]
115
+ )
116
+ if end < 0:
117
+ return (
118
+ (
119
+ "%s/%d is an element of %s, which a path does not replace alone: give %s a whole list, or "
120
+ + "write a property of the element, as %s/%d/<property>."
121
+ )
122
+ % [head, place, called, head, head, place]
123
+ )
124
+ return ""
125
+
126
+
127
+ static func _built_into(held: Resource, home: String) -> bool:
128
+ if not held.is_built_in():
129
+ return false
59
130
  var file: String = held.resource_path.get_slice("::", 0)
60
- return held if home.is_empty() or file.is_empty() or file == home else null
131
+ return home.is_empty() or file.is_empty() or file == home
61
132
 
62
133
 
63
134
  ## The file [param target] is saved in: its scene's for a node, as the nodes of an instance are
@@ -184,9 +255,11 @@ static func class_called(target: Object) -> String:
184
255
  static func held_elsewhere(target: Object, name: String, home: String) -> String:
185
256
  var at: int = name.find("/")
186
257
  while at > 0:
187
- var head: String = name.left(at)
188
- var rest: String = name.substr(at + 1)
189
- var held: Resource = held_at(target, head)
258
+ var stepped: Array = _stepped(target, name, at)
259
+ var held: Resource = stepped[0]
260
+ var past: int = GdhRead.as_int(stepped[1])
261
+ var head: String = "" if held == null else name.left(past - 1)
262
+ var rest: String = "" if held == null else name.substr(past)
190
263
  var file: String = "" if held == null else held.resource_path.get_slice("::", 0)
191
264
  if held != null and not held.is_built_in():
192
265
  return (