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,5 +1,4 @@
1
1
  extends RefCounted
2
-
3
2
  ## Godot values as JSON can carry them, and JSON back into the values the engine wants.
4
3
  ##
5
4
  ## This file is the one beside the operations, and `bun run sync:gd` copies it into each addon,
@@ -10,17 +9,14 @@ extends RefCounted
10
9
 
11
10
  const GdhRead = preload("reading.gd")
12
11
  const GdhShapes = preload("value_shapes.gd")
13
-
14
12
  # What the engine carries from one to another without complaint, which is what a value written to a
15
13
  # property or handed to a parameter may arrive as. Numbers include bool because the engine counts it
16
14
  # as one, and the three text types are one string wearing three hats.
17
15
  const NUMBERS: Array[int] = [TYPE_BOOL, TYPE_INT, TYPE_FLOAT]
18
16
  const TEXTS: Array[int] = [TYPE_STRING, TYPE_STRING_NAME, TYPE_NODE_PATH]
19
-
20
17
  # 2^53. A JSON number is a double, and every whole number below this one in size has a double of
21
18
  # its own; from here on two or more share each double, so one arriving tells nobody which was sent.
22
- const EXACT: int = 9007199254740992
23
-
19
+ const EXACT: int = 9_007_199_254_740_992
24
20
  # The types that cross as a plain JSON list and have to be built back into themselves. A list is
25
21
  # what a caller can write by hand and what the serialiser answers with, and the parameter or
26
22
  # property being written is the only thing that knows which of these it wanted.
@@ -35,7 +31,6 @@ const LIST_TYPES: Array[int] = [
35
31
  TYPE_PACKED_VECTOR4_ARRAY,
36
32
  TYPE_PACKED_COLOR_ARRAY,
37
33
  ]
38
-
39
34
  # What each Godot type becomes on the wire, as one table you can read rather than an order you
40
35
  # have to trust. Keyed on typeof() rather than written as a chain of `is` tests, because the
41
36
  # order mattered: Resource had to be tested before Object or every resource came back as a bare
@@ -92,7 +87,6 @@ const SERIALISERS: Dictionary = {
92
87
  TYPE_PACKED_VECTOR4_ARRAY: "_serialize_vector4s",
93
88
  TYPE_PACKED_COLOR_ARRAY: "_serialize_colors",
94
89
  }
95
-
96
90
  # What each tag builds back into. The other half of the table above, and separate from it because
97
91
  # they are keyed differently: one by the type of a value in hand, the other by the name in a
98
92
  # dictionary that arrived from somewhere else.
@@ -144,7 +138,11 @@ func serialize_value(value: Variant) -> Variant:
144
138
  # The fixed shapes carry their components as bare floats, so an infinite one in a Vector2 is
145
139
  # tagged here, and a 32-bit one shortened; containers reach their members through this already.
146
140
  var type: int = typeof(value)
147
- return carried if type in [TYPE_ARRAY, TYPE_DICTIONARY] else _finite(carried, GdhRead.holds_singles(type))
141
+ return (
142
+ carried
143
+ if type in [TYPE_ARRAY, TYPE_DICTIONARY]
144
+ else _finite(carried, GdhRead.holds_singles(type))
145
+ )
148
146
 
149
147
 
150
148
  # [param carried] with every non-finite float in it tagged. JSON has no spelling for infinity or
@@ -172,7 +170,10 @@ func _finite(carried: Variant, single: bool = false) -> Variant:
172
170
  func _serialize_float(value: float) -> Variant:
173
171
  if is_finite(value):
174
172
  return value
175
- return {"_type": "float", "value": "nan" if is_nan(value) else ("inf" if value > 0 else "-inf")}
173
+ return {
174
+ "_type": "float",
175
+ "value": "nan" if is_nan(value) else ("inf" if value > 0 else "-inf"),
176
+ }
176
177
 
177
178
 
178
179
  # A packed float array stays the JSON list it is unless something in it has no JSON spelling.
@@ -400,8 +401,9 @@ func fitted(value: Variant, type: int) -> Variant:
400
401
  var simple: Array[int] = [TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING]
401
402
  if not simple.has(type) or not simple.has(typeof(rebuilt)):
402
403
  return rebuilt
403
- # A number or a truth value stays as sent where text is wanted, for the refusal to name. Converted,
404
- # 1 arrived as the double it is in JSON and was saved as "1.0", which is not the text anyone sends.
404
+ # A number or a truth value stays as sent where text is wanted, for the refusal to name.
405
+ # Converted, 1 arrived as the double it is in JSON and was saved as "1.0", which is not the text
406
+ # anyone sends.
405
407
  if type == TYPE_STRING and not rebuilt is String:
406
408
  return rebuilt
407
409
 
@@ -426,9 +428,10 @@ func fitted(value: Variant, type: int) -> Variant:
426
428
 
427
429
 
428
430
  ## Why [param given], meant for an int, may not be the number that was sent, or "" when it is. A
429
- ## JSON number is a double wherever it is read, so a whole number from 2^53 on arrives as the nearest
430
- ## double to the one written: 9007199254740993 sent as a number arrives as 9007199254740992, and a
431
- ## seed written that way would be stored as its neighbour with the answer saying it was written.
431
+ ## JSON number is a double wherever it is read, so a whole number from 2^53 on arrives as the
432
+ ## nearest double to the one written: 9007199254740993 sent as a number arrives as 9007199254740992,
433
+ ## and a seed written that way would be stored as its neighbour with the answer saying it was
434
+ ## written.
432
435
  static func inexact(given: Variant, type: int) -> String:
433
436
  if type != TYPE_INT or (typeof(given) != TYPE_FLOAT and typeof(given) != TYPE_INT):
434
437
  return ""
@@ -437,9 +440,9 @@ static func inexact(given: Variant, type: int) -> String:
437
440
  return ""
438
441
  return (
439
442
  (
440
- "%s is 2^53 or more, where a JSON number holds a whole number only to the nearest double,"
441
- + ' so it may not be the number sent: send the digits as {"_type": "int", "value": "..."}'
442
- + ", the form a read answers with"
443
+ "%s is 2^53 or more, where a JSON number holds a whole number only to the nearest "
444
+ + 'double, so it may not be the number sent: send the digits as {"_type": "int", '
445
+ + '"value": "..."}, the form a read answers with'
443
446
  )
444
447
  % String.num(number, 0)
445
448
  )
@@ -450,51 +453,59 @@ func _serialize_nil(_value: Variant) -> Variant:
450
453
 
451
454
 
452
455
  func _serialize_vector2(value: Vector2) -> Dictionary:
453
- return {"x": value.x, "y": value.y, "_type": "Vector2"}
456
+ return { "x": value.x, "y": value.y, "_type": "Vector2" }
454
457
 
455
458
 
456
459
  func _serialize_vector2i(value: Vector2i) -> Dictionary:
457
- return {"x": value.x, "y": value.y, "_type": "Vector2i"}
460
+ return { "x": value.x, "y": value.y, "_type": "Vector2i" }
458
461
 
459
462
 
460
463
  func _serialize_vector3(value: Vector3) -> Dictionary:
461
- return {"x": value.x, "y": value.y, "z": value.z, "_type": "Vector3"}
464
+ return { "x": value.x, "y": value.y, "z": value.z, "_type": "Vector3" }
462
465
 
463
466
 
464
467
  func _serialize_vector3i(value: Vector3i) -> Dictionary:
465
- return {"x": value.x, "y": value.y, "z": value.z, "_type": "Vector3i"}
468
+ return { "x": value.x, "y": value.y, "z": value.z, "_type": "Vector3i" }
466
469
 
467
470
 
468
471
  func _serialize_vector4(value: Vector4) -> Dictionary:
469
- return {"x": value.x, "y": value.y, "z": value.z, "w": value.w, "_type": "Vector4"}
472
+ return { "x": value.x, "y": value.y, "z": value.z, "w": value.w, "_type": "Vector4" }
470
473
 
471
474
 
472
475
  func _serialize_vector4i(value: Vector4i) -> Dictionary:
473
- return {"x": value.x, "y": value.y, "z": value.z, "w": value.w, "_type": "Vector4i"}
476
+ return { "x": value.x, "y": value.y, "z": value.z, "w": value.w, "_type": "Vector4i" }
474
477
 
475
478
 
476
479
  func _serialize_rect2(value: Rect2) -> Dictionary:
477
480
  return {
478
- "position": serialize_value(value.position), "size": serialize_value(value.size), "_type": "Rect2"
481
+ "position": serialize_value(value.position),
482
+ "size": serialize_value(value.size),
483
+ "_type": "Rect2",
479
484
  }
480
485
 
481
486
 
482
487
  func _serialize_rect2i(value: Rect2i) -> Dictionary:
483
488
  return {
484
- "position": serialize_value(value.position), "size": serialize_value(value.size), "_type": "Rect2i"
489
+ "position": serialize_value(value.position),
490
+ "size": serialize_value(value.size),
491
+ "_type": "Rect2i",
485
492
  }
486
493
 
487
494
 
488
495
  func _serialize_plane(value: Plane) -> Dictionary:
489
- return {"normal": serialize_value(value.normal), "d": value.d, "_type": "Plane"}
496
+ return { "normal": serialize_value(value.normal), "d": value.d, "_type": "Plane" }
490
497
 
491
498
 
492
499
  func _serialize_quaternion(value: Quaternion) -> Dictionary:
493
- return {"x": value.x, "y": value.y, "z": value.z, "w": value.w, "_type": "Quaternion"}
500
+ return { "x": value.x, "y": value.y, "z": value.z, "w": value.w, "_type": "Quaternion" }
494
501
 
495
502
 
496
503
  func _serialize_aabb(value: AABB) -> Dictionary:
497
- return {"position": serialize_value(value.position), "size": serialize_value(value.size), "_type": "AABB"}
504
+ return {
505
+ "position": serialize_value(value.position),
506
+ "size": serialize_value(value.size),
507
+ "_type": "AABB",
508
+ }
498
509
 
499
510
 
500
511
  func _serialize_basis(value: Basis) -> Dictionary:
@@ -502,7 +513,7 @@ func _serialize_basis(value: Basis) -> Dictionary:
502
513
  "x": serialize_value(value.x),
503
514
  "y": serialize_value(value.y),
504
515
  "z": serialize_value(value.z),
505
- "_type": "Basis"
516
+ "_type": "Basis",
506
517
  }
507
518
 
508
519
 
@@ -511,13 +522,15 @@ func _serialize_transform2d(value: Transform2D) -> Dictionary:
511
522
  "origin": serialize_value(value.origin),
512
523
  "x": serialize_value(value.x),
513
524
  "y": serialize_value(value.y),
514
- "_type": "Transform2D"
525
+ "_type": "Transform2D",
515
526
  }
516
527
 
517
528
 
518
529
  func _serialize_transform3d(value: Transform3D) -> Dictionary:
519
530
  return {
520
- "origin": serialize_value(value.origin), "basis": serialize_value(value.basis), "_type": "Transform3D"
531
+ "origin": serialize_value(value.origin),
532
+ "basis": serialize_value(value.basis),
533
+ "_type": "Transform3D",
521
534
  }
522
535
 
523
536
 
@@ -527,22 +540,22 @@ func _serialize_projection(value: Projection) -> Dictionary:
527
540
  "y": serialize_value(value.y),
528
541
  "z": serialize_value(value.z),
529
542
  "w": serialize_value(value.w),
530
- "_type": "Projection"
543
+ "_type": "Projection",
531
544
  }
532
545
 
533
546
 
534
547
  func _serialize_color(value: Color) -> Dictionary:
535
- return {"r": value.r, "g": value.g, "b": value.b, "a": value.a, "_type": "Color"}
548
+ return { "r": value.r, "g": value.g, "b": value.b, "a": value.a, "_type": "Color" }
536
549
 
537
550
 
538
551
  func _serialize_node_path(value: NodePath) -> Dictionary:
539
- return {"path": str(value), "_type": "NodePath"}
552
+ return { "path": str(value), "_type": "NodePath" }
540
553
 
541
554
 
542
555
  # By its id, which is all an RID is from outside the server holding it, and which builds it back:
543
556
  # a viewport's RID read off one call is what RenderingServer's render timing takes in the next.
544
557
  func _serialize_rid(value: RID) -> Dictionary:
545
- return {"id": _serialize_int(value.get_id()), "_type": "RID"}
558
+ return { "id": _serialize_int(value.get_id()), "_type": "RID" }
546
559
 
547
560
 
548
561
  # A whole number from 2^53 on as its digits, because JSON numbers are doubles on the server's side
@@ -552,7 +565,7 @@ func _serialize_rid(value: RID) -> Dictionary:
552
565
  func _serialize_int(value: int) -> Variant:
553
566
  if value > -EXACT and value < EXACT:
554
567
  return value
555
- return {"_type": "int", "value": str(value)}
568
+ return { "_type": "int", "value": str(value) }
556
569
 
557
570
 
558
571
  # A packed list of 64-bit numbers stays the JSON list it is unless something in it is too large for
@@ -570,7 +583,7 @@ func _serialize_ints(value: PackedInt64Array) -> Variant:
570
583
  # A bound method, said in the terms a caller could act on: what it is on, and what it is called.
571
584
  # It cannot be rebuilt from here, and saying so is the answer rather than a silent null.
572
585
  func _serialize_callable(value: Callable) -> Dictionary:
573
- var described: Dictionary = {"method": str(value.get_method()), "_type": "Callable"}
586
+ var described: Dictionary = { "method": str(value.get_method()), "_type": "Callable" }
574
587
  var holder: Object = value.get_object()
575
588
  if holder != null:
576
589
  described["object"] = _describe_object(holder)
@@ -578,7 +591,7 @@ func _serialize_callable(value: Callable) -> Dictionary:
578
591
 
579
592
 
580
593
  func _serialize_signal(value: Signal) -> Dictionary:
581
- var described: Dictionary = {"name": str(value.get_name()), "_type": "Signal"}
594
+ var described: Dictionary = { "name": str(value.get_name()), "_type": "Signal" }
582
595
  var holder: Object = value.get_object()
583
596
  if holder != null:
584
597
  described["object"] = _describe_object(holder)
@@ -589,12 +602,14 @@ func _serialize_signal(value: Signal) -> Dictionary:
589
602
  ## int or Vector2 key was answered as its text, and a dictionary read and written back had its keys
590
603
  ## replaced by words: `{1: "a"}` came back as `{"1": "a"}`.
591
604
  func _serialize_dictionary(value: Dictionary) -> Dictionary:
592
- var texts: bool = value.keys().all(func(key: Variant) -> bool: return key is String or key is StringName)
605
+ var texts: bool = value.keys().all(
606
+ func(key: Variant) -> bool: return key is String or key is StringName
607
+ )
593
608
  if not texts:
594
609
  var entries: Array = []
595
610
  for key: Variant in value:
596
611
  entries.append([serialize_value(key), serialize_value(value[key])])
597
- return {"_type": "Dictionary", "entries": entries}
612
+ return { "_type": "Dictionary", "entries": entries }
598
613
  var serialised: Dictionary = {}
599
614
  for key: Variant in value:
600
615
  serialised[str(key)] = serialize_value(value[key])
@@ -612,7 +627,7 @@ func _serialize_array(value: Array) -> Array:
612
627
  # TileMapLayer with nothing painted yet, so a read of one carried an engine error in its answer.
613
628
  func _serialize_bytes(value: PackedByteArray) -> Dictionary:
614
629
  var text: String = "" if value.is_empty() else Marshalls.raw_to_base64(value)
615
- return {"base64": text, "size": value.size(), "_type": "PackedByteArray"}
630
+ return { "base64": text, "size": value.size(), "_type": "PackedByteArray" }
616
631
 
617
632
 
618
633
  # The packed vector and colour arrays, each element serialised the way one of them on its own is.
@@ -660,7 +675,7 @@ func _serialize_object(value: Object) -> Variant:
660
675
  if resource.resource_path.is_empty() or resource.resource_path.contains("::"):
661
676
  return _describe_built_in(resource)
662
677
  var filed: Dictionary = {
663
- "path": resource.resource_path, "class": resource.get_class(), "_type": "Resource"
678
+ "path": resource.resource_path, "class": resource.get_class(), "_type": "Resource",
664
679
  }
665
680
  # The engine class of a resource with a script is the one its script extends, so a Stats
666
681
  # file read as a Resource and nothing said it was a Stats.
@@ -673,7 +688,7 @@ func _serialize_object(value: Object) -> Variant:
673
688
  if value is Node:
674
689
  var node: Node = value
675
690
  if node.is_inside_tree():
676
- return {"path": str(node.get_path()), "class": node.get_class(), "_type": "Node"}
691
+ return { "path": str(node.get_path()), "class": node.get_class(), "_type": "Node" }
677
692
  return _describe_object(value)
678
693
 
679
694
 
@@ -683,16 +698,16 @@ func _serialize_object(value: Object) -> Variant:
683
698
  ## written back.
684
699
  func _describe_built_in(resource: Resource) -> Dictionary:
685
700
  if _describing.has(resource):
686
- return {"class": resource.get_class(), "_type": "Resource"}
701
+ return { "class": resource.get_class(), "_type": "Resource" }
687
702
  _describing.append(resource)
688
- var described: Dictionary = {"_type": resource.get_class()}
703
+ var described: Dictionary = { "_type": resource.get_class() }
689
704
  var attached: Variant = resource.get_script()
690
705
  var script: Script = null
691
706
  if attached is Script:
692
707
  script = attached
693
708
  # By the class its script declares, which a write takes as the _type and which says what it
694
- # is: as Resource with the script beside it, one answer named a Shop's built-in item that way
695
- # and the file item beside it as an Item.
709
+ # is: as Resource with the script beside it, one answer named a Shop's built-in item that
710
+ # way and the file item beside it as an Item.
696
711
  if script.get_global_name().is_empty():
697
712
  described["script"] = serialize_value(script)
698
713
  else:
@@ -741,11 +756,17 @@ static func _fresh(script: Script) -> Object:
741
756
  ## away from its default. As a bare resource it was its class and nothing else, so an input action
742
757
  ## read back from project.godot could not say whether it was bound to Space or to a joypad button.
743
758
  func _describe_input_event(event: InputEvent) -> Dictionary:
744
- var described: Dictionary = {"class": event.get_class(), "_type": "Resource", "text": event.as_text()}
759
+ var described: Dictionary = {
760
+ "class": event.get_class(), "_type": "Resource", "text": event.as_text(),
761
+ }
745
762
  for property: Dictionary in event.get_property_list():
746
763
  var usage: int = property.get("usage", 0)
747
764
  var name: String = str(property.get("name", ""))
748
- if not (usage & PROPERTY_USAGE_STORAGE) or name.begins_with("resource_") or name == "script":
765
+ if (
766
+ not (usage & PROPERTY_USAGE_STORAGE)
767
+ or name.begins_with("resource_")
768
+ or name == "script"
769
+ ):
749
770
  continue
750
771
  var held: Variant = event.get(name)
751
772
  if held == ClassDB.class_get_property_default_value(event.get_class(), name):
@@ -764,7 +785,7 @@ func _describe_input_event(event: InputEvent) -> Dictionary:
764
785
  ## different per object. None of it is invented: every field is left out when there is nothing to
765
786
  ## put in it, because a key holding "" is a worse answer than a key that is not there.
766
787
  func _describe_object(value: Object) -> Dictionary:
767
- var described: Dictionary = {"class": value.get_class(), "_type": "Object"}
788
+ var described: Dictionary = { "class": value.get_class(), "_type": "Object" }
768
789
  # Asked as a Variant and narrowed, because get_script answers one and an object without a
769
790
  # script answers null: casting that to Script is the unsafe cast the engine refuses to compile.
770
791
  var attached: Variant = value.get_script()
@@ -892,7 +913,10 @@ func _build_transform3d(fields: Dictionary) -> Transform3D:
892
913
 
893
914
  func _build_projection(fields: Dictionary) -> Projection:
894
915
  return Projection(
895
- _vector4_at(fields, "x"), _vector4_at(fields, "y"), _vector4_at(fields, "z"), _vector4_at(fields, "w")
916
+ _vector4_at(fields, "x"),
917
+ _vector4_at(fields, "y"),
918
+ _vector4_at(fields, "z"),
919
+ _vector4_at(fields, "w")
896
920
  )
897
921
 
898
922
 
@@ -1,12 +1,10 @@
1
1
  extends RefCounted
2
-
3
2
  ## How each engine type built from fields is written: the fields it needs, the ones it reads when
4
3
  ## they are there, and what a refusal says about a value that is not one.
5
4
  ##
6
5
  ## This file is the one beside the operations, and `bun run sync:gd` copies it into each addon.
7
6
 
8
7
  const GdhRead = preload("reading.gd")
9
-
10
8
  ## The classes that store what the inspector shows, and a write takes, under other names: a Curve
11
9
  ## keeps its points as _data, numbers and modes in one list, and its range as _limits, where the
12
10
  ## inspector and resource_edit modify have point_count, point_0/position and min_value. A read
@@ -17,7 +15,6 @@ const STORED_APART: Dictionary[String, Array] = {
17
15
  "Curve3D": ["_data"],
18
16
  }
19
17
  const HEADINGS: int = PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_GROUP | PROPERTY_USAGE_SUBGROUP
20
-
21
18
  ## What each packed array holds, one value of which every element is fitted to.
22
19
  const PACKED_ELEMENTS: Dictionary = {
23
20
  TYPE_PACKED_BYTE_ARRAY: TYPE_INT,
@@ -43,7 +40,6 @@ const LIST_TAGS: Dictionary = {
43
40
  "PackedVector4Array": TYPE_PACKED_VECTOR4_ARRAY,
44
41
  "PackedColorArray": TYPE_PACKED_COLOR_ARRAY,
45
42
  }
46
-
47
43
  # What each tag has to carry before it is built. A tag naming a type whose keys are not there is a
48
44
  # tag somebody wrote by mistake or wrote for a different shape, and building one out of defaults
49
45
  # answers with a Transform2D of zeros where the caller meant something else entirely. Unbuilt, it
@@ -254,7 +250,9 @@ static func remedy(value: Variant, type: int) -> String:
254
250
  if shape.is_empty():
255
251
  return ""
256
252
  return (
257
- _unread(value, type) + _no_number(value, type) + " A %s is sent as %s." % [type_string(type), shape]
253
+ _unread(value, type)
254
+ + _no_number(value, type)
255
+ + " A %s is sent as %s." % [type_string(type), shape]
258
256
  )
259
257
 
260
258
 
@@ -288,7 +286,8 @@ static func _unread(value: Variant, type: int) -> String:
288
286
  var _named: bool = named.append('"%s"' % key)
289
287
  var fields_called: String = "field called" if named.size() == 1 else "fields called"
290
288
  var note: String = (
291
- " A %s has no %s %s, so the value is not read as one" % [tag, fields_called, " or ".join(named)]
289
+ " A %s has no %s %s, so the value is not read as one"
290
+ % [tag, fields_called, " or ".join(named)]
292
291
  )
293
292
  if left.has("type") and not fields.has("_type"):
294
293
  return note + ': a value names its type under "_type".'
@@ -1,6 +1,5 @@
1
1
  class_name GdhBench
2
2
  extends RefCounted
3
-
4
3
  ## Work played a step a frame, for the script profiler. The engine sends the profiler what each
5
4
  ## frame called and holds names for only so many functions a frame, so work played inside one frame
6
5
  ## comes back with most of its functions unnamed; spread over frames, every step is named.
@@ -11,9 +10,9 @@ extends RefCounted
11
10
  ## get_tree().quit()
12
11
 
13
12
 
14
- ## Calls [param step] once a frame, up to [param most] times, and stops early when it returns
15
- ## false. Answers how many steps ran under "steps", and under "ms_each" the wall-clock milliseconds a
16
- ## step took on average, the step alone and not the frame around it.
13
+ ## Calls [param step] once a frame, up to [param most] times, and stops early when it returns false.
14
+ ## Answers how many steps ran under "steps", and under "ms_each" the wall-clock milliseconds a step
15
+ ## took on average, the step alone and not the frame around it.
17
16
  static func each_frame(tree: SceneTree, most: int, step: Callable) -> Dictionary:
18
17
  var steps: int = 0
19
18
  var spent_usec: int = 0
@@ -25,4 +24,4 @@ static func each_frame(tree: SceneTree, most: int, step: Callable) -> Dictionary
25
24
  steps += 1
26
25
  if going is bool and going == false:
27
26
  break
28
- return {"steps": steps, "ms_each": spent_usec / 1000.0 / maxf(1.0, float(steps))}
27
+ return { "steps": steps, "ms_each": spent_usec / 1000.0 / maxf(1.0, float(steps)) }
@@ -34,7 +34,9 @@ static func wheel(at: Vector2, up: bool = true) -> InputEventMouseButton:
34
34
 
35
35
  ## The mouse moved to [param at] by [param moved], holding [param held], a mask of buttons such
36
36
  ## as MOUSE_BUTTON_MASK_LEFT for a drag.
37
- static func motion(at: Vector2, moved: Vector2 = Vector2.ZERO, held: int = 0) -> InputEventMouseMotion:
37
+ static func motion(
38
+ at: Vector2, moved: Vector2 = Vector2.ZERO, held: int = 0
39
+ ) -> InputEventMouseMotion:
38
40
  var made: InputEventMouseMotion = InputEventMouseMotion.new()
39
41
  made.position = at
40
42
  made.global_position = at
@@ -43,8 +45,8 @@ static func motion(at: Vector2, moved: Vector2 = Vector2.ZERO, held: int = 0) ->
43
45
  return made
44
46
 
45
47
 
46
- ## [param key_pressed] pressed, or released when [param pressed] is false. The key is set as both the
47
- ## keycode and the physical keycode, so a binding to either matches it.
48
+ ## [param key_pressed] pressed, or released when [param pressed] is false. The key is set as both
49
+ ## the keycode and the physical keycode, so a binding to either matches it.
48
50
  static func key(key_pressed: Key, pressed: bool = true) -> InputEventKey:
49
51
  var made: InputEventKey = InputEventKey.new()
50
52
  made.keycode = key_pressed
@@ -72,8 +74,11 @@ static func axis(axis_moved: JoyAxis, value: float, device: int = 0) -> InputEve
72
74
  return made
73
75
 
74
76
 
75
- ## The action [param action_named] pressed at [param strength], or released when [param pressed] is false.
76
- static func action(action_named: StringName, pressed: bool = true, strength: float = 1.0) -> InputEventAction:
77
+ ## The action [param action_named] pressed at [param strength], or released when [param pressed] is
78
+ ## false.
79
+ static func action(
80
+ action_named: StringName, pressed: bool = true, strength: float = 1.0
81
+ ) -> InputEventAction:
77
82
  var made: InputEventAction = InputEventAction.new()
78
83
  made.action = action_named
79
84
  made.pressed = pressed
@@ -6,10 +6,11 @@ extends RefCounted
6
6
  ## A bench whose run `i` depends on `i` alone (its seed worked out from the index, nothing carried
7
7
  ## from one run to the next) calls [method outcomes] for each arm with the number of runs and a
8
8
  ## callable playing run `i`. Run on its own, the scene plays every run here, as it always did. Under
9
- ## `gdharness spread`, each worker engine plays every Nth run from its own index and leaves what each
10
- ## run answered; then one more engine runs the scene to gather, and there [method outcomes] plays
11
- ## nothing and answers every run's outcome, read back as the type it went in as. The bench folds them
12
- ## in run order either way, so a spread table is the same table to the last digit, floats included.
9
+ ## `gdharness spread`, each worker engine plays every Nth run from its own index and leaves what
10
+ ## each run answered; then one more engine runs the scene to gather, and there [method outcomes]
11
+ ## plays nothing and answers every run's outcome, read back as the type it went in as. The bench
12
+ ## folds them in run order either way, so a spread table is the same table to the last digit, floats
13
+ ## included.
13
14
  ##
14
15
  ## An outcome is a plain value: a number, a string, a vector, or an array or dictionary of them. An
15
16
  ## object cannot be handed from one engine to another, so one is refused with an error.
@@ -18,7 +19,8 @@ extends RefCounted
18
19
  const SHARE: String = "--gdh-share="
19
20
  ## What it tells the engine gathering: how many workers left outcomes.
20
21
  const GATHER: String = "--gdh-share-gather="
21
- ## Where the workers leave their outcomes, an absolute path, since each engine has its own `user://`.
22
+ ## Where the workers leave their outcomes, an absolute path, since each engine has its own
23
+ ## `user://`.
22
24
  const INTO: String = "--gdh-share-dir="
23
25
  ## What a worker prints as it goes, which `gdharness spread` reads to say how far each has got.
24
26
  const PROGRESS: String = "gdharness share: %s %d of %d runs"
@@ -67,7 +69,9 @@ static func dealt(runs: int) -> PackedInt32Array:
67
69
  static func outcomes(arm: String, runs: int, play: Callable) -> Array:
68
70
  _learn()
69
71
  if _arms.has(arm):
70
- push_error("GdhShare: the arm %s was played twice in one run; give each arm its own name" % arm)
72
+ push_error(
73
+ "GdhShare: the arm %s was played twice in one run; give each arm its own name" % arm
74
+ )
71
75
  return []
72
76
  _arms[arm] = true
73
77
  if gathering():
@@ -83,7 +87,10 @@ static func outcomes(arm: String, runs: int, play: Callable) -> Array:
83
87
  if not wrong.is_empty():
84
88
  push_error(
85
89
  (
86
- "GdhShare: run %d of %s answered %s, which cannot be handed from one engine to another"
90
+ (
91
+ "GdhShare: run %d of %s answered %s, which cannot be handed from one "
92
+ + "engine to another"
93
+ )
87
94
  % [run, arm, wrong]
88
95
  )
89
96
  )
@@ -109,7 +116,9 @@ static func added(
109
116
  var total: Dictionary[String, int] = {}
110
117
  for outcome: Variant in counted:
111
118
  if not outcome is Dictionary:
112
- push_error("GdhShare.added: an outcome is %s, not a dictionary" % type_string(typeof(outcome)))
119
+ push_error(
120
+ "GdhShare.added: an outcome is %s, not a dictionary" % type_string(typeof(outcome))
121
+ )
113
122
  continue
114
123
  var counts: Dictionary = outcome
115
124
  for key: Variant in counts:
@@ -117,7 +126,10 @@ static func added(
117
126
  var count: Variant = counts[key]
118
127
  if not count is int:
119
128
  push_error(
120
- "GdhShare.added: %s is %s, not a whole number" % [named, type_string(typeof(count))]
129
+ (
130
+ "GdhShare.added: %s is %s, not a whole number"
131
+ % [named, type_string(typeof(count))]
132
+ )
121
133
  )
122
134
  continue
123
135
  var now: int = count
@@ -133,10 +145,12 @@ static func added(
133
145
  ## Leaves one arm's outcomes, then the line saying so, which `gdharness spread` checks the share
134
146
  ## against; the outcomes first, so a line is never there without them.
135
147
  static func _leave(arm: String, runs: int, by_index: Dictionary[int, Variant]) -> void:
136
- var left: Dictionary = {"arm": arm, "runs": runs, "outcomes": by_index}
137
- if not _appended("worker-%d.bin" % _index, func(file: FileAccess) -> bool: return file.store_var(left)):
148
+ var left: Dictionary = { "arm": arm, "runs": runs, "outcomes": by_index }
149
+ if not _appended(
150
+ "worker-%d.bin" % _index, func(file: FileAccess) -> bool: return file.store_var(left)
151
+ ):
138
152
  return
139
- var said: String = JSON.stringify({"arm": arm, "runs": runs, "played": by_index.size()})
153
+ var said: String = JSON.stringify({ "arm": arm, "runs": runs, "played": by_index.size() })
140
154
  var _noted: bool = _appended(
141
155
  "worker-%d.arms" % _index, func(file: FileAccess) -> bool: return file.store_line(said)
142
156
  )
@@ -149,7 +163,9 @@ static func _appended(name: String, write: Callable) -> bool:
149
163
  path, FileAccess.READ_WRITE if FileAccess.file_exists(path) else FileAccess.WRITE
150
164
  )
151
165
  if file == null:
152
- push_error("GdhShare: cannot write %s: %s" % [path, error_string(FileAccess.get_open_error())])
166
+ push_error(
167
+ "GdhShare: cannot write %s: %s" % [path, error_string(FileAccess.get_open_error())]
168
+ )
153
169
  return false
154
170
  file.seek_end()
155
171
  var wrote: bool = write.call(file)
@@ -168,8 +184,8 @@ static func _gathered(arm: String, runs: int) -> Array:
168
184
  push_error(
169
185
  (
170
186
  (
171
- "GdhShare: no worker played the arm %s, so this run went another way than theirs; "
172
- + "which arms a bench plays must depend on its command line alone"
187
+ "GdhShare: no worker played the arm %s, so this run went another way than "
188
+ + "theirs; which arms a bench plays must depend on its command line alone"
173
189
  )
174
190
  % arm
175
191
  )
@@ -190,7 +206,7 @@ static func _gathered(arm: String, runs: int) -> Array:
190
206
  push_error("GdhShare: no worker played run %d of %s" % [run, arm])
191
207
  return []
192
208
  ordered.append(held[run])
193
- var said: String = JSON.stringify({"arm": arm, "runs": runs, "played": runs})
209
+ var said: String = JSON.stringify({ "arm": arm, "runs": runs, "played": runs })
194
210
  var _noted: bool = _appended(
195
211
  "gathered.arms", func(file: FileAccess) -> bool: return file.store_line(said)
196
212
  )
@@ -205,7 +221,9 @@ static func _read_workers() -> void:
205
221
  var path: String = _directory.path_join("worker-%d.bin" % worker)
206
222
  var file: FileAccess = FileAccess.open(path, FileAccess.READ)
207
223
  if file == null:
208
- _unread = "GdhShare: cannot read %s: %s" % [path, error_string(FileAccess.get_open_error())]
224
+ _unread = (
225
+ "GdhShare: cannot read %s: %s" % [path, error_string(FileAccess.get_open_error())]
226
+ )
209
227
  return
210
228
  while file.get_position() < file.get_length():
211
229
  _unread = _took(file.get_var(), path)
@@ -260,7 +278,9 @@ static func _learn() -> void:
260
278
  elif given.begins_with(INTO):
261
279
  _directory = given.trim_prefix(INTO)
262
280
  if (_index >= 0 or _gathering > 0) and _directory.is_empty():
263
- push_error("GdhShare: a spread engine was given no %s<directory> to share outcomes in" % INTO)
281
+ push_error(
282
+ "GdhShare: a spread engine was given no %s<directory> to share outcomes in" % INTO
283
+ )
264
284
 
265
285
 
266
286
  ## What in [param value] cannot be written by one engine and read by another, or empty.
@@ -1,5 +1,4 @@
1
1
  extends Node
2
-
3
2
  ## gdUnit4 suites run inside a played scene, which the engine's script profiler sees and a script
4
3
  ## run with `-s` never does. `editor_run start` given `suites` plays this scene with
5
4
  ## [constant RUNNER] naming the runner `gdharness test` uses, where the server ships it, followed by
@@ -20,8 +19,9 @@ func _ready() -> void:
20
19
  push_error(
21
20
  (
22
21
  (
23
- "gdharness suites: no runner at '%s'. This scene is played by editor_run start with suites,"
24
- + " which names the runner after %s; it does nothing played any other way."
22
+ "gdharness suites: no runner at '%s'. This scene is played by editor_run start "
23
+ + "with suites, which names the runner after %s; it does nothing played any "
24
+ + "other way."
25
25
  )
26
26
  % [path, RUNNER]
27
27
  )
@@ -10,7 +10,6 @@ extends RefCounted
10
10
 
11
11
  ## How long [method until] and [method still] wait by default, in milliseconds.
12
12
  const MOST_MS: int = 30000
13
-
14
13
  ## Frames in a row with no tween running before [method still] counts the tree as still. A layout
15
14
  ## often starts its slide a frame after the change that asks for it, so the frame straight after
16
15
  ## had no tween yet and passed for still.
@@ -28,7 +27,9 @@ static func until(tree: SceneTree, done: Callable, most_ms: int = MOST_MS) -> bo
28
27
 
29
28
 
30
29
  ## Whether the tree ran no tween for [param quiet_frames] frames in a row within [param most_ms].
31
- static func still(tree: SceneTree, quiet_frames: int = QUIET_FRAMES, most_ms: int = MOST_MS) -> bool:
30
+ static func still(
31
+ tree: SceneTree, quiet_frames: int = QUIET_FRAMES, most_ms: int = MOST_MS
32
+ ) -> bool:
32
33
  var began: int = Time.get_ticks_msec()
33
34
  var quiet: int = 0
34
35
  while quiet < quiet_frames: