gdharness 1.3.41 → 1.3.43

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 (107) hide show
  1. package/build/cli.js +131 -47
  2. package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
  3. package/build/godot/addons/gdharness_editor/animation_reads.gd +84 -35
  4. package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
  5. package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
  6. package/build/godot/addons/gdharness_editor/file_reads.gd +114 -39
  7. package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
  8. package/build/godot/addons/gdharness_editor/headless_check.gd +94 -41
  9. package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
  10. package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
  11. package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
  12. package/build/godot/addons/gdharness_editor/reading.gd +37 -12
  13. package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
  14. package/build/godot/addons/gdharness_editor/scene_file.gd +136 -79
  15. package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
  16. package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
  17. package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
  18. package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
  19. package/build/godot/addons/gdharness_editor/tools/animation_states.gd +41 -28
  20. package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +84 -50
  21. package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
  22. package/build/godot/addons/gdharness_editor/tools/class_tools.gd +34 -30
  23. package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
  24. package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
  25. package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
  26. package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
  27. package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +181 -107
  28. package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
  29. package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +75 -43
  30. package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
  31. package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
  32. package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +66 -0
  33. package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd.uid +1 -0
  34. package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +171 -62
  35. package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
  36. package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
  37. package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
  38. package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
  39. package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
  40. package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
  41. package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
  42. package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
  43. package/build/godot/addons/gdharness_runtime/reading.gd +37 -12
  44. package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
  45. package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +153 -148
  46. package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
  47. package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
  48. package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
  49. package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
  50. package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
  51. package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
  52. package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
  53. package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +38 -20
  54. package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
  55. package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
  56. package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
  57. package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
  58. package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
  59. package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
  60. package/build/godot/addons/gdharness_runtime/runtime_touch.gd +211 -0
  61. package/build/godot/addons/gdharness_runtime/runtime_touch.gd.uid +1 -0
  62. package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
  63. package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
  64. package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
  65. package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
  66. package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
  67. package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
  68. package/build/godot/addons/gdharness_tests/bench.gd +4 -5
  69. package/build/godot/addons/gdharness_tests/event.gd +10 -5
  70. package/build/godot/addons/gdharness_tests/share.gd +38 -18
  71. package/build/godot/addons/gdharness_tests/suites.gd +3 -3
  72. package/build/godot/addons/gdharness_tests/wait.gd +3 -2
  73. package/build/godot/loader/loader.gd +9 -9
  74. package/build/godot/operations/animation_reads.gd +84 -35
  75. package/build/godot/operations/audio_buses.gd +48 -19
  76. package/build/godot/operations/class_cache.gd +16 -11
  77. package/build/godot/operations/classdb_queries.gd +89 -44
  78. package/build/godot/operations/declared_values.gd +68 -32
  79. package/build/godot/operations/dependencies.gd +139 -93
  80. package/build/godot/operations/editor_tools.gd +9 -10
  81. package/build/godot/operations/export_presets.gd +100 -54
  82. package/build/godot/operations/file_reads.gd +114 -39
  83. package/build/godot/operations/file_walk.gd +12 -5
  84. package/build/godot/operations/gdscript_analysis.gd +105 -66
  85. package/build/godot/operations/gdscript_authoring.gd +138 -39
  86. package/build/godot/operations/godot_operations.gd +17 -11
  87. package/build/godot/operations/import_pipeline.gd +110 -59
  88. package/build/godot/operations/input_actions.gd +63 -39
  89. package/build/godot/operations/patterns.gd +3 -1
  90. package/build/godot/operations/plugins.gd +36 -16
  91. package/build/godot/operations/project_config.gd +144 -27
  92. package/build/godot/operations/project_diagnostics.gd +24 -11
  93. package/build/godot/operations/project_file.gd +16 -16
  94. package/build/godot/operations/project_validation.gd +71 -44
  95. package/build/godot/operations/property_paths.gd +22 -12
  96. package/build/godot/operations/property_values.gd +143 -78
  97. package/build/godot/operations/reading.gd +37 -12
  98. package/build/godot/operations/rename_checks.gd +2 -2
  99. package/build/godot/operations/resource_files.gd +11 -9
  100. package/build/godot/operations/same_values.gd +4 -4
  101. package/build/godot/operations/scene_connections.gd +27 -13
  102. package/build/godot/operations/script_check.gd +52 -49
  103. package/build/godot/operations/serialisation.gd +75 -51
  104. package/build/godot/operations/setting_reads.gd +7 -6
  105. package/build/godot/operations/value_shapes.gd +5 -6
  106. package/build/godot/tests/listed.gd +321 -268
  107. package/package.json +1 -1
@@ -1,8 +1,7 @@
1
1
  @tool
2
2
  extends Node
3
-
4
- ## Animations and animation trees, edited in the open editor or, for a project no editor serves, by a
5
- ## headless engine.
3
+ ## Animations and animation trees, edited in the open editor or, for a project no editor serves, by
4
+ ## a headless engine.
6
5
 
7
6
  const GdhAnimationReads = preload("../animation_reads.gd")
8
7
  const GdhHeadlessCheck = preload("../headless_check.gd")
@@ -11,9 +10,10 @@ const GdhRead = preload("../reading.gd")
11
10
  const GdhSceneFile = preload("../scene_file.gd")
12
11
  const GdhSceneUids = preload("../scene_uids.gd")
13
12
  const GdhSerialisation = preload("../serialisation.gd")
14
-
15
13
  const LOOP_MODES: Dictionary = {
16
- "none": Animation.LOOP_NONE, "linear": Animation.LOOP_LINEAR, "pingpong": Animation.LOOP_PINGPONG
14
+ "none": Animation.LOOP_NONE,
15
+ "linear": Animation.LOOP_LINEAR,
16
+ "pingpong": Animation.LOOP_PINGPONG,
17
17
  }
18
18
 
19
19
  var _editor_plugin: EditorPlugin = null
@@ -74,7 +74,9 @@ func _not_of_kind(scene: GdhSceneFile, node: Node, node_path: String, kind: Stri
74
74
 
75
75
  ## Writes [param scene] once [param check] passes, then the files of [param homes], answering
76
76
  ## [param answer] or a refusal.
77
- func _finish(scene: GdhSceneFile, check: Callable, homes: Dictionary, answer: Dictionary) -> Dictionary:
77
+ func _finish(
78
+ scene: GdhSceneFile, check: Callable, homes: Dictionary, answer: Dictionary
79
+ ) -> Dictionary:
78
80
  if not Engine.is_editor_hint():
79
81
  for file: Variant in homes:
80
82
  var home: Resource = homes[file]
@@ -85,9 +87,9 @@ func _finish(scene: GdhSceneFile, check: Callable, homes: Dictionary, answer: Di
85
87
  (
86
88
  (
87
89
  (
88
- "Nothing was written: %s holds a resource with a script that is not a tool, and what "
89
- + "that script changed when a headless engine loaded it cannot be told apart from the "
90
- + "edit. "
90
+ "Nothing was written: %s holds a resource with a script that "
91
+ + "is not a tool, and what that script changed when a headless "
92
+ + "engine loaded it cannot be told apart from the edit. "
91
93
  )
92
94
  % file
93
95
  )
@@ -102,7 +104,7 @@ func _finish(scene: GdhSceneFile, check: Callable, homes: Dictionary, answer: Di
102
104
  var resource: Resource = homes[file]
103
105
  var saving: Error = GdhSceneUids.save_keeping_uid(resource, str(file))
104
106
  if saving != OK:
105
- return {"ok": false, "error": "Failed to save %s: %s" % [file, error_string(saving)]}
107
+ return { "ok": false, "error": "Failed to save %s: %s" % [file, error_string(saving)] }
106
108
  if Engine.is_editor_hint():
107
109
  EditorInterface.get_resource_filesystem().update_file(str(file))
108
110
  return answer
@@ -112,7 +114,10 @@ func _finish(scene: GdhSceneFile, check: Callable, homes: Dictionary, answer: Di
112
114
  ## engine ran as it loaded the file.
113
115
  func _scripted(resource: Resource) -> bool:
114
116
  var script: Script = resource.get_script()
115
- return (script != null and not script.is_tool()) or GdhHeadlessCheck.holds_scripted_embedded(resource, {})
117
+ return (
118
+ (script != null and not script.is_tool())
119
+ or GdhHeadlessCheck.holds_scripted_embedded(resource, {})
120
+ )
116
121
 
117
122
 
118
123
  func _parse_json_maybe(value: Variant) -> Variant:
@@ -160,11 +165,11 @@ func _homes(scene: GdhSceneFile, held: Array) -> Array:
160
165
  false,
161
166
  (
162
167
  (
163
- "The %s is kept in %s, not in %s, and an edit here would not be saved there. Edit it "
164
- + "where it is kept instead."
168
+ "The %s is kept in %s, not in %s, and an edit here would not be saved there. "
169
+ + "Edit it where it is kept instead."
165
170
  )
166
171
  % [entry[1], at.get_slice("::", 0), scene.path]
167
- )
172
+ ),
168
173
  ]
169
174
  return [true, homes]
170
175
 
@@ -198,7 +203,9 @@ func _library_of(player: AnimationPlayer, animation_name: String) -> AnimationLi
198
203
  ## The state machine at [param state_machine_path] in [param anim_tree], with the files it is kept
199
204
  ## in, as [machine, homes, why not].
200
205
  func _machine(scene: GdhSceneFile, anim_tree: AnimationTree, state_machine_path: String) -> Array:
201
- var sm: AnimationNodeStateMachine = GdhAnimationReads.state_machine(anim_tree, state_machine_path)
206
+ var sm: AnimationNodeStateMachine = GdhAnimationReads.state_machine(
207
+ anim_tree, state_machine_path
208
+ )
202
209
  if not sm:
203
210
  return [null, {}, GdhAnimationReads.no_machine(anim_tree, state_machine_path)]
204
211
  var homes: Array = _homes(scene, [[sm, "state machine"]])
@@ -225,7 +232,7 @@ func read_animations(args: Dictionary) -> Dictionary:
225
232
  var player_node_path: String = str(args.get("playerNodePath", "."))
226
233
  var animation_name: String = str(args.get("animationName", ""))
227
234
  if scene_path.strip_edges() == "res://":
228
- return {"ok": false, "error": "Missing scenePath"}
235
+ return { "ok": false, "error": "Missing scenePath" }
229
236
 
230
237
  var opened: Array = _read_at(scene_path, player_node_path, "AnimationPlayer")
231
238
  var scene: GdhSceneFile = opened[0]
@@ -250,18 +257,23 @@ func read_animation_states(args: Dictionary) -> Dictionary:
250
257
  var anim_tree_path: String = str(args.get("animTreePath", ""))
251
258
  var state_machine_path: String = str(args.get("stateMachinePath", ""))
252
259
  if scene_path.strip_edges() == "res://":
253
- return {"ok": false, "error": "Missing scenePath"}
260
+ return { "ok": false, "error": "Missing scenePath" }
254
261
  if anim_tree_path.is_empty():
255
- return {"ok": false, "error": "Missing animTreePath"}
262
+ return { "ok": false, "error": "Missing animTreePath" }
256
263
 
257
264
  var opened: Array = _read_at(scene_path, anim_tree_path, "AnimationTree")
258
265
  var scene: GdhSceneFile = opened[0]
259
266
  if opened[1] == null:
260
267
  return opened[2]
261
268
  var anim_tree: AnimationTree = opened[1]
262
- var player: AnimationPlayer = anim_tree.get_node_or_null(anim_tree.anim_player) as AnimationPlayer
269
+ var reached: Node = anim_tree.get_node_or_null(anim_tree.anim_player)
270
+ var player: AnimationPlayer = reached as AnimationPlayer
263
271
  var player_path: String = "" if player == null else scene.path_of(player)
264
- return _read_in(scene, GdhAnimationReads.states(anim_tree, state_machine_path, player, player_path))
272
+ var unplayed: String = GdhAnimationReads.no_player(str(anim_tree.anim_player), reached)
273
+ return _read_in(
274
+ scene,
275
+ GdhAnimationReads.states(anim_tree, state_machine_path, player, player_path, unplayed)
276
+ )
265
277
 
266
278
 
267
279
  # =============================================================================
@@ -274,18 +286,18 @@ func create_animation(args: Dictionary) -> Dictionary:
274
286
  var loop_mode_name: String = str(args.get("loopMode", "none"))
275
287
 
276
288
  if scene_path.strip_edges() == "res://":
277
- return {"ok": false, "error": "Missing scenePath"}
289
+ return { "ok": false, "error": "Missing scenePath" }
278
290
  if animation_name.strip_edges().is_empty():
279
- return {"ok": false, "error": "Missing animationName"}
291
+ return { "ok": false, "error": "Missing animationName" }
280
292
  var named: String = _name_refusal(animation_name)
281
293
  if not named.is_empty():
282
- return {"ok": false, "error": named}
294
+ return { "ok": false, "error": named }
283
295
  var loop_modes: Dictionary = LOOP_MODES
284
296
  if not loop_modes.has(loop_mode_name):
285
- return {"ok": false, "error": "Unsupported loopMode: " + loop_mode_name}
297
+ return { "ok": false, "error": "Unsupported loopMode: " + loop_mode_name }
286
298
  var timing: String = _timing_refusal(args)
287
299
  if not timing.is_empty():
288
- return {"ok": false, "error": timing}
300
+ return { "ok": false, "error": timing }
289
301
 
290
302
  var opened: Array = _open_at(scene_path, player_node_path, "AnimationPlayer")
291
303
  var scene: GdhSceneFile = opened[0]
@@ -306,7 +318,9 @@ func create_animation(args: Dictionary) -> Dictionary:
306
318
  anim.length = GdhRead.as_float(args.get("length", 1.0), 1.0)
307
319
  anim.loop_mode = GdhRead.as_int(loop_modes[loop_mode_name]) as Animation.LoopMode
308
320
  anim.step = GdhRead.as_float(args.get("step", 0.1), 0.1)
309
- var called: String = animation_name.get_slice("/", 1) if animation_name.contains("/") else animation_name
321
+ var called: String = (
322
+ animation_name.get_slice("/", 1) if animation_name.contains("/") else animation_name
323
+ )
310
324
  # As the editor names a new one: the file keeps it as resource_name, which the inspector shows.
311
325
  anim.resource_name = called
312
326
  var add_err: Error = anim_lib.add_animation(StringName(called), anim)
@@ -323,10 +337,12 @@ func create_animation(args: Dictionary) -> Dictionary:
323
337
  "ok": true,
324
338
  "animationName": animation_name,
325
339
  "length": GdhAnimationReads.held_seconds(anim.length),
326
- "loopMode": loop_mode_name
340
+ "loopMode": loop_mode_name,
327
341
  }
328
342
  if library[2]:
329
- answer["libraryMade"] = animation_name.get_slice("/", 0) if animation_name.contains("/") else ""
343
+ answer["libraryMade"] = (
344
+ animation_name.get_slice("/", 0) if animation_name.contains("/") else ""
345
+ )
330
346
  var files: Dictionary = homes[1]
331
347
  return _finish(scene, check, files, answer)
332
348
 
@@ -337,8 +353,8 @@ static func _name_refusal(animation_name: String) -> String:
337
353
  if animation_name.count("/") > 1:
338
354
  return (
339
355
  (
340
- "%s names a library and an animation in it with one slash, as moves/walk; a library holds no "
341
- + "libraries."
356
+ "%s names a library and an animation in it with one slash, as moves/walk; a "
357
+ + "library holds no libraries."
342
358
  )
343
359
  % animation_name
344
360
  )
@@ -368,7 +384,9 @@ static func _past_length(anim: Animation, animation_name: String) -> String:
368
384
 
369
385
  ## The pastLength sentence for [param past], keys of [param anim] each named by its track's path and
370
386
  ## time, or "" for none.
371
- static func _past_sentence(anim: Animation, animation_name: String, past: PackedStringArray) -> String:
387
+ static func _past_sentence(
388
+ anim: Animation, animation_name: String, past: PackedStringArray
389
+ ) -> String:
372
390
  if past.is_empty():
373
391
  return ""
374
392
  return (
@@ -403,7 +421,10 @@ static func _timing_refusal(args: Dictionary) -> String:
403
421
  if args.has("length"):
404
422
  var length: Variant = args["length"]
405
423
  if not (length is float or length is int) or GdhRead.as_float(length) <= 0.0:
406
- return "length is the animation's length in seconds, more than 0, and %s is not." % _given(length)
424
+ return (
425
+ "length is the animation's length in seconds, more than 0, and %s is not."
426
+ % _given(length)
427
+ )
407
428
  if args.has("step"):
408
429
  var step: Variant = args["step"]
409
430
  if not (step is float or step is int) or GdhRead.as_float(step) < 0.0:
@@ -439,16 +460,19 @@ func set_animation(args: Dictionary) -> Dictionary:
439
460
  var animation_name: String = str(args.get("animationName", ""))
440
461
  var loop_mode_name: String = str(args.get("loopMode", ""))
441
462
  if scene_path.strip_edges() == "res://":
442
- return {"ok": false, "error": "Missing scenePath"}
463
+ return { "ok": false, "error": "Missing scenePath" }
443
464
  if animation_name.strip_edges().is_empty():
444
- return {"ok": false, "error": "Missing animationName"}
465
+ return { "ok": false, "error": "Missing animationName" }
445
466
  if not (args.has("length") or args.has("loopMode") or args.has("step")):
446
- return {"ok": false, "error": "set changes length, loopMode or step, and was given none of them."}
467
+ return {
468
+ "ok": false,
469
+ "error": "set changes length, loopMode or step, and was given none of them.",
470
+ }
447
471
  if args.has("loopMode") and not LOOP_MODES.has(loop_mode_name):
448
- return {"ok": false, "error": "Unsupported loopMode: " + loop_mode_name}
472
+ return { "ok": false, "error": "Unsupported loopMode: " + loop_mode_name }
449
473
  var timing: String = _timing_refusal(args)
450
474
  if not timing.is_empty():
451
- return {"ok": false, "error": timing}
475
+ return { "ok": false, "error": timing }
452
476
 
453
477
  var found: Array = _animation_at(scene_path, player_node_path, animation_name)
454
478
  if found[1] == null:
@@ -475,7 +499,10 @@ func set_animation(args: Dictionary) -> Dictionary:
475
499
  if copy == null or not copy.has_animation(StringName(animation_name)):
476
500
  return "%s would not be in the scene when it loads." % animation_name
477
501
  if not is_equal_approx(copy.get_animation(StringName(animation_name)).length, length):
478
- return "%s would not be %s s long when the scene loads." % [animation_name, _seconds(length)]
502
+ return (
503
+ "%s would not be %s s long when the scene loads."
504
+ % [animation_name, _seconds(length)]
505
+ )
479
506
  return ""
480
507
  var answer: Dictionary = {
481
508
  "ok": true,
@@ -500,12 +527,14 @@ func rename_animation(args: Dictionary) -> Dictionary:
500
527
  var animation_name: String = str(args.get("animationName", ""))
501
528
  var new_name: String = str(args.get("newName", "")).strip_edges()
502
529
  if scene_path.strip_edges() == "res://":
503
- return {"ok": false, "error": "Missing scenePath"}
530
+ return { "ok": false, "error": "Missing scenePath" }
504
531
  if animation_name.strip_edges().is_empty():
505
- return {"ok": false, "error": "Missing animationName"}
532
+ return { "ok": false, "error": "Missing animationName" }
506
533
  if new_name.is_empty():
507
- return {"ok": false, "error": "Missing newName"}
508
- var library_name: String = animation_name.get_slice("/", 0) if animation_name.contains("/") else ""
534
+ return { "ok": false, "error": "Missing newName" }
535
+ var library_name: String = (
536
+ animation_name.get_slice("/", 0) if animation_name.contains("/") else ""
537
+ )
509
538
  var prefix: String = "" if library_name.is_empty() else library_name + "/"
510
539
  if not prefix.is_empty() and new_name.begins_with(prefix):
511
540
  new_name = new_name.trim_prefix(prefix)
@@ -515,15 +544,18 @@ func rename_animation(args: Dictionary) -> Dictionary:
515
544
  "error":
516
545
  (
517
546
  (
518
- "rename keeps an animation in its library (%s), so newName is its name there, with "
519
- + "no library before a slash."
547
+ "rename keeps an animation in its library (%s), so newName is its name there, "
548
+ + "with no library before a slash."
520
549
  )
521
550
  % ("the default one" if library_name.is_empty() else library_name)
522
551
  ),
523
552
  }
524
553
  for forbidden: String in [":", ",", "["]:
525
554
  if new_name.contains(forbidden):
526
- return {"ok": false, "error": "An animation's name cannot hold : , or [, and %s does." % new_name}
555
+ return {
556
+ "ok": false,
557
+ "error": "An animation's name cannot hold : , or [, and %s does." % new_name,
558
+ }
527
559
  var new_full: String = prefix + new_name
528
560
 
529
561
  var found: Array = _animation_at(scene_path, player_node_path, animation_name)
@@ -553,7 +585,7 @@ func rename_animation(args: Dictionary) -> Dictionary:
553
585
  # As the editor's rename sets it: the library's key alone left the file's resource_name, which
554
586
  # the inspector shows, on the old name.
555
587
  player.get_animation(StringName(new_full)).resource_name = new_name
556
- var answer: Dictionary = {"ok": true, "animationName": new_full, "was": animation_name}
588
+ var answer: Dictionary = { "ok": true, "animationName": new_full, "was": animation_name }
557
589
  if autoplayed:
558
590
  answer["autoplay"] = new_full
559
591
  var followed: Array = []
@@ -581,9 +613,9 @@ func remove_animation(args: Dictionary) -> Dictionary:
581
613
  var player_node_path: String = str(args.get("playerNodePath", "."))
582
614
  var animation_name: String = str(args.get("animationName", ""))
583
615
  if scene_path.strip_edges() == "res://":
584
- return {"ok": false, "error": "Missing scenePath"}
616
+ return { "ok": false, "error": "Missing scenePath" }
585
617
  if animation_name.strip_edges().is_empty():
586
- return {"ok": false, "error": "Missing animationName"}
618
+ return { "ok": false, "error": "Missing animationName" }
587
619
 
588
620
  var found: Array = _animation_at(scene_path, player_node_path, animation_name)
589
621
  if found[1] == null:
@@ -594,12 +626,14 @@ func remove_animation(args: Dictionary) -> Dictionary:
594
626
  var homes: Array = _homes(scene, [[library, "animation library"]])
595
627
  if not homes[0]:
596
628
  return scene.refuse(str(homes[1]))
597
- var called: String = animation_name.get_slice("/", 1) if animation_name.contains("/") else animation_name
629
+ var called: String = (
630
+ animation_name.get_slice("/", 1) if animation_name.contains("/") else animation_name
631
+ )
598
632
  var autoplayed: bool = str(player.autoplay) == animation_name
599
633
  library.remove_animation(StringName(called))
600
634
  if player.has_animation(StringName(animation_name)):
601
635
  return scene.refuse("The library did not let go of %s." % animation_name)
602
- var answer: Dictionary = {"ok": true, "removed": animation_name}
636
+ var answer: Dictionary = { "ok": true, "removed": animation_name }
603
637
  if autoplayed:
604
638
  player.autoplay = ""
605
639
  answer["autoplayCleared"] = true
@@ -1,8 +1,7 @@
1
1
  @tool
2
2
  extends "animation_tools.gd"
3
-
4
- ## The tracks and keys of an animation, beside the players and libraries the script it extends edits,
5
- ## whose helpers it shares.
3
+ ## The tracks and keys of an animation, beside the players and libraries the script it extends
4
+ ## edits, whose helpers it shares.
6
5
 
7
6
 
8
7
  # =============================================================================
@@ -15,19 +14,19 @@ func add_animation_track(args: Dictionary) -> Dictionary:
15
14
  var given_track: Variant = args.get("track", {})
16
15
 
17
16
  if scene_path.strip_edges() == "res://":
18
- return {"ok": false, "error": "Missing scenePath"}
17
+ return { "ok": false, "error": "Missing scenePath" }
19
18
  if animation_name.strip_edges().is_empty():
20
- return {"ok": false, "error": "Missing animationName"}
19
+ return { "ok": false, "error": "Missing animationName" }
21
20
  var track: Dictionary = given_track if given_track is Dictionary else {}
22
21
  if track.is_empty():
23
- return {"ok": false, "error": "Missing track"}
24
- # The schema leaves keyframes out of what track requires, since remove_track finds a track without
25
- # them.
22
+ return { "ok": false, "error": "Missing track" }
23
+ # The schema leaves keyframes out of what track requires, since remove_track finds a track
24
+ # without them.
26
25
  if not track.has("keyframes"):
27
- return {"ok": false, "error": "Missing track.keyframes"}
26
+ return { "ok": false, "error": "Missing track.keyframes" }
28
27
  var keyed: Array = _keyframes(track)
29
28
  if not keyed[0]:
30
- return {"ok": false, "error": keyed[1]}
29
+ return { "ok": false, "error": keyed[1] }
31
30
 
32
31
  # Asked of the player, which knows every library: looking only in the default one refused
33
32
  # "moves/walk" as missing.
@@ -48,13 +47,16 @@ func add_animation_track(args: Dictionary) -> Dictionary:
48
47
  target_path = "."
49
48
  var target: Node = _animated(player, target_path)
50
49
  if target == null:
51
- return scene.refuse(
52
- (
50
+ return (
51
+ scene
52
+ . refuse(
53
53
  (
54
- "No node at %s from the player's root node, %s, which is what the track path is read "
55
- + "against."
54
+ (
55
+ "No node at %s from the player's root node, %s, which is what the track "
56
+ + "path is read against."
57
+ )
58
+ % [target_path, str(player.root_node)]
56
59
  )
57
- % [target_path, str(player.root_node)]
58
60
  )
59
61
  )
60
62
  var keyframes: Array = keyed[1]
@@ -120,7 +122,12 @@ func add_animation_track(args: Dictionary) -> Dictionary:
120
122
  ## animates: two tracks for one path both play, the later overriding the earlier, and a key meant
121
123
  ## to extend the motion was split off where reading the animation showed two halves.
122
124
  func _add_track(
123
- anim: Animation, track: Dictionary, target: Node, target_path: String, keyframes: Array, replacing: bool
125
+ anim: Animation,
126
+ track: Dictionary,
127
+ target: Node,
128
+ target_path: String,
129
+ keyframes: Array,
130
+ replacing: bool
124
131
  ) -> Array:
125
132
  var track_type: String = str(track.get("type", ""))
126
133
  var keys: Array = []
@@ -148,7 +155,7 @@ func _add_track(
148
155
  return _not_added("keyframes[%d].args must be a list." % index)
149
156
  var raw: Array = given
150
157
  var arguments: Array = _fitted(target, method_name, _parse_method_args(raw))
151
- keys.append({"method": method_name, "args": arguments})
158
+ keys.append({ "method": method_name, "args": arguments })
152
159
  if misfit.is_empty():
153
160
  misfit = _key_misfit(target, method_name, arguments, index)
154
161
  method_found = target.has_method(method_name)
@@ -156,7 +163,10 @@ func _add_track(
156
163
  else:
157
164
  return _not_added(
158
165
  (
159
- "add_track makes property and method tracks, and track.type is %s; remove_track takes any."
166
+ (
167
+ "add_track makes property and method tracks, and track.type is %s; "
168
+ + "remove_track takes any."
169
+ )
160
170
  % track_type
161
171
  )
162
172
  )
@@ -178,14 +188,16 @@ func _add_track(
178
188
  return _not_added(
179
189
  (
180
190
  (
181
- "Track %d already animates %s and has a key at %s s, which keyframes[%d] would "
182
- + "replace. Nothing was written; replaceKeys true replaces it."
191
+ "Track %d already animates %s and has a key at %s s, which "
192
+ + "keyframes[%d] would replace. Nothing was written; replaceKeys true "
193
+ + "replaces it."
183
194
  )
184
195
  % [track_idx, str(path), _seconds(time), index]
185
196
  )
186
197
  )
187
- # A method key's value is its call, {"method": ..., "args": [...]}. The time is as asked:
188
- # the key's own, read back from a scene's 32-bit times, puts 0.1 at 0.100000001490116.
198
+ # A method key's value is its call, {"method": ..., "args": [...]}. The time is as
199
+ # asked: the key's own, read back from a scene's 32-bit times, puts 0.1 at
200
+ # 0.100000001490116.
189
201
  (
190
202
  replaced
191
203
  . append(
@@ -228,7 +240,9 @@ static func _fitted(target: Node, method: String, arguments: Array) -> Array:
228
240
  declared = GdhRead.as_int(parameter.get("type", TYPE_NIL))
229
241
  if value is float and declared != TYPE_FLOAT:
230
242
  var number: float = value
231
- if is_finite(number) and number == floorf(number) and absf(number) < 9007199254740992.0:
243
+ if (is_finite(number)
244
+ and number == floorf(number)
245
+ and absf(number) < 9_007_199_254_740_992.0):
232
246
  value = int(number)
233
247
  fitted.append(value)
234
248
  return fitted
@@ -256,10 +270,16 @@ static func _key_misfit(target: Node, method: String, arguments: Array, index: i
256
270
  else ("1 argument" if arguments.size() == 1 else "%d arguments" % arguments.size())
257
271
  )
258
272
  if arguments.size() < needed:
259
- return "keyframes[%d] calls %s with %s, and it needs %d%s" % [index, method, passed, needed, fails]
273
+ return (
274
+ "keyframes[%d] calls %s with %s, and it needs %d%s"
275
+ % [index, method, passed, needed, fails]
276
+ )
260
277
  if arguments.size() > parameters.size():
261
278
  var most: String = "none" if parameters.is_empty() else "at most %d" % parameters.size()
262
- return "keyframes[%d] calls %s with %s, and it takes %s%s" % [index, method, passed, most, fails]
279
+ return (
280
+ "keyframes[%d] calls %s with %s, and it takes %s%s"
281
+ % [index, method, passed, most, fails]
282
+ )
263
283
  for at: int in arguments.size():
264
284
  var parameter: Dictionary = parameters[at]
265
285
  var taken_type: int = GdhRead.as_int(parameter.get("type", TYPE_NIL))
@@ -276,7 +296,7 @@ static func _key_misfit(target: Node, method: String, arguments: Array, index: i
276
296
  method,
277
297
  str(parameter.get("name", "")),
278
298
  type_string(taken_type),
279
- fails
299
+ fails,
280
300
  ]
281
301
  )
282
302
  return ""
@@ -293,22 +313,22 @@ func remove_animation_track(args: Dictionary) -> Dictionary:
293
313
  var animation_name: String = str(args.get("animationName", ""))
294
314
  var given_track: Variant = args.get("track", {})
295
315
  if scene_path.strip_edges() == "res://":
296
- return {"ok": false, "error": "Missing scenePath"}
316
+ return { "ok": false, "error": "Missing scenePath" }
297
317
  if animation_name.strip_edges().is_empty():
298
- return {"ok": false, "error": "Missing animationName"}
318
+ return { "ok": false, "error": "Missing animationName" }
299
319
  var track: Dictionary = given_track if given_track is Dictionary else {}
300
320
  if track.is_empty():
301
- return {"ok": false, "error": "Missing track"}
321
+ return { "ok": false, "error": "Missing track" }
302
322
  var track_type: String = str(track.get("type", ""))
303
323
  if not track_type in GdhAnimationReads.TRACK_TYPE_NAMES.values():
304
- return {"ok": false, "error": "Unsupported track.type: " + track_type}
324
+ return { "ok": false, "error": "Unsupported track.type: " + track_type }
305
325
  var node_path: String = str(track.get("nodePath", ""))
306
326
  var property: String = str(track.get("property", ""))
307
327
  var shape: Array = [track_type, node_path, property]
308
328
  var method: String = str(track.get("method", "")) if track_type == "method" else ""
309
329
  var read_times: Variant = _times_of(args.get("times"))
310
330
  if read_times is String:
311
- return {"ok": false, "error": read_times}
331
+ return { "ok": false, "error": read_times }
312
332
  var times: Array = read_times
313
333
 
314
334
  var found: Array = _animation_at(scene_path, player_node_path, animation_name)
@@ -335,7 +355,7 @@ func remove_animation_track(args: Dictionary) -> Dictionary:
335
355
  % [
336
356
  animation_name,
337
357
  track_type,
338
- node_path if property.is_empty() else "%s:%s" % [node_path, property]
358
+ node_path if property.is_empty() else "%s:%s" % [node_path, property],
339
359
  ]
340
360
  )
341
361
  if held.is_empty():
@@ -353,7 +373,9 @@ func remove_animation_track(args: Dictionary) -> Dictionary:
353
373
  var timed: Array = _keys_at(anim, calling, times)
354
374
  if timed[1] != "":
355
375
  var on: String = node_path if property.is_empty() else "%s:%s" % [node_path, property]
356
- return scene.refuse("%s's %s track on %s %s" % [animation_name, track_type, on, timed[1]])
376
+ return scene.refuse(
377
+ "%s's %s track on %s %s" % [animation_name, track_type, on, timed[1]]
378
+ )
357
379
  calling = timed[0]
358
380
  var keys: int = 0
359
381
  var tracks_removed: int = 0
@@ -383,7 +405,7 @@ func remove_animation_track(args: Dictionary) -> Dictionary:
383
405
  if loaded.get_track_count() != left or _key_total(loaded) != keys_left:
384
406
  return "the track would still be in %s when the scene loads." % animation_name
385
407
  return ""
386
- var removed: Dictionary = {"type": track_type, "nodePath": node_path}
408
+ var removed: Dictionary = { "type": track_type, "nodePath": node_path }
387
409
  if not property.is_empty():
388
410
  removed["property"] = property
389
411
  if not method.is_empty():
@@ -432,8 +454,8 @@ static func _times_of(given: Variant) -> Variant:
432
454
 
433
455
 
434
456
  ## Of the keys [param calling] names, as [method _keys_calling] answers them, the ones at
435
- ## [param times], as [[[track, key]...], ""], or with the second the words refusing a time none is at.
436
- ## Removing a key took removing its whole track, so moving one key in time rewrote every other.
457
+ ## [param times], as [[[track, key]...], ""], or with the second the words refusing a time none is
458
+ ## at. Removing a key took removing its whole track, so moving one key in time rewrote every other.
437
459
  static func _keys_at(anim: Animation, calling: Array, times: Array) -> Array:
438
460
  var at: Array = []
439
461
  var held: PackedStringArray = []
@@ -457,7 +479,10 @@ static func _keys_at(anim: Animation, calling: Array, times: Array) -> Array:
457
479
  var _named: bool = named.append(str(given))
458
480
  return [
459
481
  at,
460
- "has no key at %s s; its keys are at %s s. Nothing was removed." % [", ".join(named), ", ".join(held)]
482
+ (
483
+ "has no key at %s s; its keys are at %s s. Nothing was removed."
484
+ % [", ".join(named), ", ".join(held)]
485
+ ),
461
486
  ]
462
487
 
463
488
 
@@ -483,7 +508,9 @@ static func _key_total(anim: Animation) -> int:
483
508
  static func _track_shape(anim: Animation, index: int) -> Array:
484
509
  var path: NodePath = anim.track_get_path(index)
485
510
  return [
486
- GdhAnimationReads.TRACK_TYPE_NAMES.get(anim.track_get_type(index), str(anim.track_get_type(index))),
511
+ GdhAnimationReads.TRACK_TYPE_NAMES.get(
512
+ anim.track_get_type(index), str(anim.track_get_type(index))
513
+ ),
487
514
  str(path.get_concatenated_names()),
488
515
  str(path.get_concatenated_subnames()),
489
516
  ]
@@ -508,7 +535,8 @@ func _keyframes(track: Dictionary) -> Array:
508
535
  var seconds: float = GdhRead.as_float(time)
509
536
  if times.has(seconds):
510
537
  return [
511
- false, "keyframes[%d] and [%d] are both at %s seconds." % [times[seconds], index, seconds]
538
+ false,
539
+ "keyframes[%d] and [%d] are both at %s seconds." % [times[seconds], index, seconds],
512
540
  ]
513
541
  times[seconds] = index
514
542
  return [true, keyframes]
@@ -530,7 +558,9 @@ func _key_values(target: Node, prop_name: String, keyframes: Array) -> Array:
530
558
  # A subname such as position:x keys one component, which is a number.
531
559
  var component: Variant = _properties.parse(raw, TYPE_FLOAT)
532
560
  if not component is float:
533
- return [false, "keyframes[%d].value keys %s, which is a number." % [index, prop_name]]
561
+ return [
562
+ false, "keyframes[%d].value keys %s, which is a number." % [index, prop_name],
563
+ ]
534
564
  values.append(component)
535
565
  continue
536
566
  var value: Array = _properties.value_for(target, declared, raw)