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,6 +1,5 @@
1
1
  @tool
2
2
  extends Node
3
-
4
3
  ## The global classes the running editor is holding.
5
4
  ##
6
5
  ## The editor fixes this list when it starts and adds to it only from a filesystem scan, and
@@ -51,10 +50,10 @@ func set_editor_plugin(plugin: EditorPlugin) -> void:
51
50
  func reload_script(args: Dictionary) -> Dictionary:
52
51
  var asked: String = str(args.get("scriptPath", ""))
53
52
  if asked.is_empty():
54
- return {"ok": false, "error": "scriptPath is required"}
53
+ return { "ok": false, "error": "scriptPath is required" }
55
54
  var path: String = _spelled_as_on_disk(asked)
56
55
  if not ResourceLoader.exists(path):
57
- return {"ok": false, "error": "No script at " + path}
56
+ return { "ok": false, "error": "No script at " + path }
58
57
 
59
58
  # The copy the editor holds, when it holds one, and otherwise a load that reads the file, rather
60
59
  # than load(): a load recompiles a script whose base has been reloaded from the text it holds,
@@ -63,11 +62,13 @@ func reload_script(args: Dictionary) -> Dictionary:
63
62
  # the reload below compiled it clean.
64
63
  var cached: Resource = ResourceLoader.get_cached_ref(path)
65
64
  var loaded: Resource = (
66
- cached if cached != null else ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE)
65
+ cached
66
+ if cached != null
67
+ else ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE)
67
68
  )
68
69
  var script: GDScript = loaded as GDScript
69
70
  if script == null:
70
- return {"ok": false, "error": path + " is not a GDScript"}
71
+ return { "ok": false, "error": path + " is not a GDScript" }
71
72
 
72
73
  # What the copy had before anything touched it, which is the reading that shows the fault rather
73
74
  # than the one that mends it. Without it a caller cannot tell a copy that was already current
@@ -82,7 +83,10 @@ func reload_script(args: Dictionary) -> Dictionary:
82
83
  # method added since is still absent from the method list.
83
84
  var reader: FileAccess = FileAccess.open(path, FileAccess.READ)
84
85
  if reader == null:
85
- return {"ok": false, "error": "Could not read " + path + ": " + str(FileAccess.get_open_error())}
86
+ return {
87
+ "ok": false,
88
+ "error": "Could not read " + path + ": " + str(FileAccess.get_open_error()),
89
+ }
86
90
  var previous: String = script.source_code
87
91
  var text: String = reader.get_as_text()
88
92
  reader.close()
@@ -90,11 +94,11 @@ func reload_script(args: Dictionary) -> Dictionary:
90
94
  # Godot keeps one parse of each script for other scripts to resolve its class through, and a
91
95
  # reload drops that parse only when the text it compiles differs from the text that was parsed.
92
96
  # A parse that failed because a class it names was not yet known has the file's own text, so it
93
- # outlived every reload: the class answered with all its methods while each script naming it read
94
- # "because of a parser error" until the editor restarted, for as long as anything held the parse,
95
- # such as a file open in an editor's language server. Compiling once with a line more makes the
96
- # texts differ, which drops that parse and those of the scripts that resolved through it; the
97
- # file's own text is compiled below.
97
+ # outlived every reload: the class answered with all its methods while each script naming it
98
+ # read "because of a parser error" until the editor restarted, for as long as anything held the
99
+ # parse, such as a file open in an editor's language server. Compiling once with a line more
100
+ # makes the texts differ, which drops that parse and those of the scripts that resolved through
101
+ # it; the file's own text is compiled below.
98
102
  script.source_code = text + "\n"
99
103
  var _dropped: Error = script.reload(true)
100
104
  script.source_code = text
@@ -103,11 +107,11 @@ func reload_script(args: Dictionary) -> Dictionary:
103
107
  # caller needs then: a failure travels back as its message alone, and a project met one and
104
108
  # could not tell whether the copy had been damaged by it or before it.
105
109
  #
106
- # And the old text is compiled again. A failed reload leaves the object unusable while its member
107
- # lists read as before, measured on 4.7.2: it can make no instance, and an instance it already made
108
- # has lost its methods, and the old text put back uncompiled leaves it that way. Compiling the text
109
- # it was built from puts it back, and whether that worked is said, since the text may no longer
110
- # compile against what it names.
110
+ # And the old text is compiled again. A failed reload leaves the object unusable while its
111
+ # member lists read as before, measured on 4.7.2: it can make no instance, and an instance it
112
+ # already made has lost its methods, and the old text put back uncompiled leaves it that way.
113
+ # Compiling the text it was built from puts it back, and whether that worked is said, since the
114
+ # text may no longer compile against what it names.
111
115
  var failed: Error = script.reload(true)
112
116
  var answer: Dictionary = {
113
117
  "ok": true,
@@ -129,8 +133,8 @@ func reload_script(args: Dictionary) -> Dictionary:
129
133
  return answer
130
134
 
131
135
 
132
- ## Which of [code]scriptPaths[/code] the editor holds a compiled copy of whose text is not the file's,
133
- ## without loading or reloading anything. A script compiled against such a copy fails on the
136
+ ## Which of [code]scriptPaths[/code] the editor holds a compiled copy of whose text is not the
137
+ ## file's, without loading or reloading anything. A script compiled against such a copy fails on the
134
138
  ## members the file has gained, and a reload of it fails the same way until the copy is reloaded
135
139
  ## first; the rescan that met this blamed the new classes the script also named, which were fine.
136
140
  ##
@@ -140,7 +144,7 @@ func reload_script(args: Dictionary) -> Dictionary:
140
144
  func scripts_behind(args: Dictionary) -> Dictionary:
141
145
  var given: Variant = args.get("scriptPaths", [])
142
146
  if not given is Array:
143
- return {"ok": false, "error": "scriptPaths must be a list of res:// paths"}
147
+ return { "ok": false, "error": "scriptPaths must be a list of res:// paths" }
144
148
  var asked: Array = given
145
149
  var unsaved: PackedStringArray = []
146
150
  if Engine.is_editor_hint():
@@ -163,13 +167,13 @@ func scripts_behind(args: Dictionary) -> Dictionary:
163
167
  edited.append(path)
164
168
  else:
165
169
  behind.append(path)
166
- return {"ok": true, "behind": behind, "unsavedInEditor": edited}
170
+ return { "ok": true, "behind": behind, "unsavedInEditor": edited }
167
171
 
168
172
 
169
- ## Has the script editor's tabs reread what changed on disk, as the editor does when its window takes
170
- ## the focus, which a hidden editor's never does. A tab with unsaved edits is left alone and named:
171
- ## saving it writes its text over the file, and rereading would ask a question nobody can answer in a
172
- ## hidden editor's dialog.
173
+ ## Has the script editor's tabs reread what changed on disk, as the editor does when its window
174
+ ## takes the focus, which a hidden editor's never does. A tab with unsaved edits is left alone and
175
+ ## named: saving it writes its text over the file, and rereading would ask a question nobody can
176
+ ## answer in a hidden editor's dialog.
173
177
  func _reread_open_tabs(path: String, answer: Dictionary) -> void:
174
178
  # The engine fixtures reload from a script run outside any editor, where there are no tabs and
175
179
  # EditorInterface has none of its methods.
@@ -223,11 +227,11 @@ func _method_names(script: GDScript) -> Array[String]:
223
227
 
224
228
 
225
229
  ## The script's constants, those of the scripts it extends included as its methods include theirs,
226
- ## and the keys of each one that is a Dictionary as `Kind.SHORT`, which is how the copy holds a named
227
- ## enum: a stale enum member is denied as a member of the enum rather than of the class. A constant
228
- ## Dictionary that is not an enum is listed the same way, since the map does not tell the two apart.
229
- ## The engine's map holds only the script's own, so a script extending a class_name listed every
230
- ## method it inherited and none of the constants.
230
+ ## and the keys of each one that is a Dictionary as `Kind.SHORT`, which is how the copy holds a
231
+ ## named enum: a stale enum member is denied as a member of the enum rather than of the class. A
232
+ ## constant Dictionary that is not an enum is listed the same way, since the map does not tell the
233
+ ## two apart. The engine's map holds only the script's own, so a script extending a class_name
234
+ ## listed every method it inherited and none of the constants.
231
235
  func _constant_names(script: GDScript) -> Array[String]:
232
236
  var names: Array[String] = []
233
237
  var holder: Script = script
@@ -250,7 +254,7 @@ func _constant_names(script: GDScript) -> Array[String]:
250
254
 
251
255
  func global_classes(_args: Dictionary) -> Dictionary:
252
256
  if not _editor_plugin:
253
- return {"ok": false, "error": "Editor plugin unavailable"}
257
+ return { "ok": false, "error": "Editor plugin unavailable" }
254
258
 
255
259
  var filesystem: EditorFileSystem = EditorInterface.get_resource_filesystem()
256
260
  var names: Array[String] = []
@@ -1,6 +1,5 @@
1
1
  @tool
2
2
  extends Node
3
-
4
3
  ## The editor's view of the files on disk: scans, the reimports asked for, where each stands, and
5
4
  ## files moved under it.
6
5
 
@@ -8,20 +7,17 @@ const GdhRead = preload("../reading.gd")
8
7
  const GdhSceneFile = preload("../scene_file.gd")
9
8
 
10
9
  var _editor_plugin: EditorPlugin = null
11
-
12
10
  ## How many scans the editor has completed, counted off `sources_changed`, which it emits at the end
13
11
  ## of every scan once the reimport the scan found is done: the one moment a scan is over. Neither
14
12
  ## flag it offers says so. A threaded scan stops reporting itself when its thread finishes, and its
15
13
  ## import runs a frame or more later when the thread is joined; an editor in the background took
16
14
  ## long enough over that frame that a rescan answered before the import of 211 changed scenes began.
17
15
  var _scans_completed: int = 0
18
-
19
16
  ## When the last scan completed, on the engine's clock, or -1 before the first. The editor writes
20
17
  ## the class cache a frame after it stops reporting a scan, measured on 4.7.2, so a game started
21
18
  ## in between reads a file being rewritten; how long ago the scan ended is what tells a caller
22
19
  ## whether that write can still be coming.
23
20
  var _scan_finished_at_msec: int = -1
24
-
25
21
  ## How many reimports asked for through [method reimport_files] have finished. Counted here rather
26
22
  ## than off `resources_reimported`, which a scan's own import emits as well.
27
23
  var _reimports_completed: int = 0
@@ -53,7 +49,7 @@ func _scan_completed(_sources_exist: bool) -> void:
53
49
  ## another scan.
54
50
  func rescan_filesystem(args: Dictionary) -> Dictionary:
55
51
  if not _editor_plugin:
56
- return {"ok": false, "error": "Editor plugin unavailable"}
52
+ return { "ok": false, "error": "Editor plugin unavailable" }
57
53
 
58
54
  var filesystem: EditorFileSystem = EditorInterface.get_resource_filesystem()
59
55
  # Not over a scan or an import the editor is already running: a scan asked for then starts a
@@ -62,13 +58,13 @@ func rescan_filesystem(args: Dictionary) -> Dictionary:
62
58
  var busy: bool = filesystem.is_scanning() or filesystem.is_importing()
63
59
  var started: bool = false
64
60
  var completed_before: int = _scans_completed
65
- var uids: Dictionary = {"reread": [], "duplicated": []}
61
+ var uids: Dictionary = { "reread": [], "duplicated": [] }
66
62
  if not GdhRead.as_bool(args.get("statusOnly", false)) and not busy:
67
63
  uids = _reread_changed_uids(filesystem)
68
- # Files the caller has just written, moved or deleted, read again one by one. The scan finds a
69
- # script that appeared and leaves the global class of one that has gone in the editor's list,
70
- # which it then writes back into the class cache at a path that is not there; reading the gone
71
- # path again is what drops it.
64
+ # Files the caller has just written, moved or deleted, read again one by one. The scan finds
65
+ # a script that appeared and leaves the global class of one that has gone in the editor's
66
+ # list, which it then writes back into the class cache at a path that is not there; reading
67
+ # the gone path again is what drops it.
72
68
  var named: Variant = args.get("updateFiles", [])
73
69
  if named is Array:
74
70
  var paths: Array = named
@@ -137,14 +133,14 @@ func _reread_changed_uids(filesystem: EditorFileSystem) -> Dictionary:
137
133
  reread.append(path)
138
134
  reread.sort()
139
135
  duplicated.sort()
140
- return {"reread": reread, "duplicated": duplicated}
136
+ return { "reread": reread, "duplicated": duplicated }
141
137
 
142
138
 
143
139
  ## Every `.uid` under [param directory], skipping what the editor skips: hidden directories, any
144
140
  ## holding a `.gdignore`, and any below the project's own that holds a `project.godot` of its own,
145
- ## which the editor passes over as another project. A nested project's UIDs are never in the editor's
146
- ## table, so without that last one its files would be read again on every rescan, and one holding a
147
- ## copy of an outer file's `.uid` named as a duplicate on disk.
141
+ ## which the editor passes over as another project. A nested project's UIDs are never in the
142
+ ## editor's table, so without that last one its files would be read again on every rescan, and one
143
+ ## holding a copy of an outer file's `.uid` named as a duplicate on disk.
148
144
  func _uid_files(directory: String, found: Array[String]) -> void:
149
145
  var listing: DirAccess = DirAccess.open(directory)
150
146
  if listing == null or FileAccess.file_exists(directory.path_join(".gdignore")):
@@ -166,12 +162,13 @@ func _uid_files(directory: String, found: Array[String]) -> void:
166
162
  ## Apart from `rescan_filesystem` because asking must not start or count anything.
167
163
  func scan_status(_args: Dictionary) -> Dictionary:
168
164
  if not _editor_plugin:
169
- return {"ok": false, "error": "Editor plugin unavailable"}
165
+ return { "ok": false, "error": "Editor plugin unavailable" }
170
166
  var filesystem: EditorFileSystem = EditorInterface.get_resource_filesystem()
171
- # The scenes open in tabs, the one shown and the ones holding unsaved edits: a scene edit on disk
172
- # meets what the editor holds of it, and nothing said which scenes those were. A tab of a scene
173
- # never saved has no path, and a new project's editor opens with an empty one, so it is left out
174
- # of the open; one with edits is kept among the unsaved, as the edits a close would lose.
167
+ # The scenes open in tabs, the one shown and the ones holding unsaved edits: a scene edit on
168
+ # disk meets what the editor holds of it, and nothing said which scenes those were. A tab of a
169
+ # scene never saved has no path, and a new project's editor opens with an empty one, so it is
170
+ # left out of the open; one with edits is kept among the unsaved, as the edits a close would
171
+ # lose.
175
172
  var shown: Node = EditorInterface.get_edited_scene_root()
176
173
  var open: Array[String] = []
177
174
  open.assign(Array(EditorInterface.get_open_scenes()).filter(_has_path))
@@ -204,14 +201,14 @@ func _has_path(path: String) -> bool:
204
201
  ## while the editor scans or imports, since `reimport_files` refuses to run inside an import.
205
202
  func reimport_files(args: Dictionary) -> Dictionary:
206
203
  if not _editor_plugin:
207
- return {"ok": false, "error": "Editor plugin unavailable"}
204
+ return { "ok": false, "error": "Editor plugin unavailable" }
208
205
  var paths: Array[String] = []
209
206
  var given: Variant = args.get("paths", [])
210
207
  if given is Array:
211
208
  for path: Variant in given:
212
209
  paths.append(str(path))
213
210
  if paths.is_empty():
214
- return {"ok": false, "error": "reimport_files needs paths"}
211
+ return { "ok": false, "error": "reimport_files needs paths" }
215
212
  var filesystem: EditorFileSystem = EditorInterface.get_resource_filesystem()
216
213
  var busy: bool = filesystem.is_scanning() or filesystem.is_importing()
217
214
  if not busy:
@@ -282,7 +279,12 @@ func files_moved(args: Dictionary) -> Dictionary:
282
279
  reloaded.append(scene)
283
280
  reloaded.sort()
284
281
  unsaved.sort()
285
- return {"ok": true, "retargetedTabs": retargeted, "reloadedScenes": reloaded, "unsavedScenes": unsaved}
282
+ return {
283
+ "ok": true,
284
+ "retargetedTabs": retargeted,
285
+ "reloadedScenes": reloaded,
286
+ "unsavedScenes": unsaved,
287
+ }
286
288
 
287
289
 
288
290
  func _reimport(paths: PackedStringArray) -> void:
@@ -1,6 +1,5 @@
1
1
  @tool
2
2
  extends RefCounted
3
-
4
3
  ## Bakes what a NavigationRegion2D or NavigationRegion3D in a scene file navigates by, as the
5
4
  ## editor's Bake button does, and saves it where the region keeps it.
6
5
  ##
@@ -13,10 +12,11 @@ extends RefCounted
13
12
 
14
13
  const GdhSceneFile = preload("../scene_file.gd")
15
14
  const GdhSceneUids = preload("../scene_uids.gd")
16
-
17
15
  ## The names NavigationPolygon.SourceGeometryMode and NavigationMesh.SourceGeometryMode give each
18
16
  ## mode, which share their values.
19
- const SOURCE_MODES: Array[String] = ["root_node_children", "groups_with_children", "groups_explicit"]
17
+ const SOURCE_MODES: Array[String] = [
18
+ "root_node_children", "groups_with_children", "groups_explicit",
19
+ ]
20
20
 
21
21
 
22
22
  ## Bakes the region [param region] of [param scene], answering what it now holds or why not.
@@ -55,13 +55,16 @@ static func bake(scene: GdhSceneFile, region: Node) -> Dictionary:
55
55
  var file: String = held.resource_path.get_slice("::", 0)
56
56
  var embedded: bool = file.is_empty() or held.resource_path.contains("::")
57
57
  if embedded and not file.is_empty() and file != scene.path:
58
- return scene.refuse(
59
- (
58
+ return (
59
+ scene
60
+ . refuse(
60
61
  (
61
- "The %s %s holds is built into %s, and a bake here cannot save that file. Bake the "
62
- + "region there, or save the %s to a file of its own."
62
+ (
63
+ "The %s %s holds is built into %s, and a bake here cannot save that file. "
64
+ + "Bake the region there, or save the %s to a file of its own."
65
+ )
66
+ % [held.get_class(), at, file, held.get_class()]
63
67
  )
64
- % [held.get_class(), at, file, held.get_class()]
65
68
  )
66
69
  )
67
70
 
@@ -78,7 +81,8 @@ static func bake(scene: GdhSceneFile, region: Node) -> Dictionary:
78
81
  }
79
82
  if made:
80
83
  answer["made"] = (
81
- "%s held no %s, so one was made and built into the scene, with the defaults." % [at, property]
84
+ "%s held no %s, so one was made and built into the scene, with the defaults."
85
+ % [at, property]
82
86
  )
83
87
  if polygons == 0:
84
88
  answer["note"] = _why_empty(held, flat, parsed)
@@ -86,17 +90,17 @@ static func bake(scene: GdhSceneFile, region: Node) -> Dictionary:
86
90
  answer["note"] = _nothing_read(scene, held)
87
91
  if not flat and not Engine.is_editor_hint() and _reads_meshes(region, held):
88
92
  answer["meshesNote"] = (
89
- "The engine's warning that it had to parse RenderingServer meshes at runtime is about a "
90
- + "game rebaking as it runs, where reading a mesh back from the GPU stalls a frame. A "
91
- + "headless engine gives it for any bake read from MeshInstance3D nodes; this one ran once "
92
- + "and is saved."
93
+ "The engine's warning that it had to parse RenderingServer meshes at runtime is about "
94
+ + "a game rebaking as it runs, where reading a mesh back from the GPU stalls a frame. "
95
+ + "A headless engine gives it for any bake read from MeshInstance3D nodes; this one "
96
+ + "ran once and is saved."
93
97
  )
94
98
 
95
99
  if not embedded:
96
100
  scene.close()
97
101
  var saving: Error = GdhSceneUids.save_keeping_uid(held, file)
98
102
  if saving != OK:
99
- return {"ok": false, "error": "Failed to save %s: %s" % [file, error_string(saving)]}
103
+ return { "ok": false, "error": "Failed to save %s: %s" % [file, error_string(saving)] }
100
104
  if Engine.is_editor_hint():
101
105
  EditorInterface.get_resource_filesystem().update_file(file)
102
106
  answer["savedTo"] = file
@@ -121,7 +125,9 @@ static func bake(scene: GdhSceneFile, region: Node) -> Dictionary:
121
125
  static func _parse_and_bake(scene: GdhSceneFile, at: String, held: Resource, flat: bool) -> bool:
122
126
  var copy: Node = scene.root.duplicate(Node.DUPLICATE_GROUPS)
123
127
  var reading: Resource = held.duplicate()
124
- var group_property: String = "source_geometry_group_name" if flat else "geometry_source_group_name"
128
+ var group_property: String = (
129
+ "source_geometry_group_name" if flat else "geometry_source_group_name"
130
+ )
125
131
  var group: String = str(held.get(group_property))
126
132
  var own_group: String = "_gdh_bake_%d" % copy.get_instance_id()
127
133
  reading.set(group_property, own_group)
@@ -136,8 +142,8 @@ static func _parse_and_bake(scene: GdhSceneFile, at: String, held: Resource, fla
136
142
  var outline: NavigationPolygon = reading
137
143
  var geometry: NavigationMeshSourceGeometryData2D = NavigationMeshSourceGeometryData2D.new()
138
144
  NavigationServer2D.parse_source_geometry_data(outline, geometry, region)
139
- # has_data() counts only traversable outlines, so a bake carving every obstacle it read would
140
- # still say it read nothing.
145
+ # has_data() counts only traversable outlines, so a bake carving every obstacle it read
146
+ # would still say it read nothing.
141
147
  found = (
142
148
  not geometry.get_obstruction_outlines().is_empty()
143
149
  or not geometry.get_projected_obstructions().is_empty()
@@ -211,12 +217,15 @@ static func _why_empty(held: Resource, flat: bool, parsed: bool) -> String:
211
217
  return (
212
218
  "The NavigationPolygon has no outlines, and a 2D bake fills only the area its "
213
219
  + "outlines enclose, less what the obstacles inside take. Give it outlines with "
214
- + "scene_node set, such as navigation_polygon/outlines [[[0, 0], [512, 0], [512, 512], "
215
- + "[0, 512]]], then bake again."
220
+ + "scene_node set, such as navigation_polygon/outlines [[[0, 0], [512, 0], [512, "
221
+ + "512], [0, 512]]], then bake again."
216
222
  )
217
223
  return (
218
224
  (
219
- "Nothing was left to walk inside the outlines once the obstacles read from %s, and the "
225
+ (
226
+ "Nothing was left to walk inside the outlines once the obstacles read from %s, "
227
+ + "and the "
228
+ )
220
229
  % _source_said(polygon.source_geometry_mode, polygon.source_geometry_group_name)
221
230
  )
222
231
  + "agent_radius %s kept from their edges, were taken out." % polygon.agent_radius
@@ -225,17 +234,27 @@ static func _why_empty(held: Resource, flat: bool, parsed: bool) -> String:
225
234
  if not parsed:
226
235
  return (
227
236
  (
228
- "No geometry was read from %s with geometry_parsed_geometry_type %s, so there was nothing to "
237
+ (
238
+ "No geometry was read from %s with geometry_parsed_geometry_type %s, so there "
239
+ + "was nothing to "
240
+ )
229
241
  % [
230
- _source_said(mesh.geometry_source_geometry_mode, mesh.geometry_source_group_name),
231
- ["mesh_instances", "static_colliders", "both"][mesh.geometry_parsed_geometry_type],
242
+ _source_said(
243
+ mesh.geometry_source_geometry_mode, mesh.geometry_source_group_name
244
+ ),
245
+ ["mesh_instances", "static_colliders", "both"][
246
+ mesh.geometry_parsed_geometry_type
247
+ ],
232
248
  ]
233
249
  )
234
- + "bake: mesh_instances reads MeshInstance3D nodes, static_colliders the shapes of physics "
235
- + "bodies on geometry_collision_mask, and both reads both."
250
+ + "bake: mesh_instances reads MeshInstance3D nodes, static_colliders the shapes of "
251
+ + "physics bodies on geometry_collision_mask, and both reads both."
236
252
  )
237
253
  return (
238
- "The geometry read gave no floor an agent of agent_height %s and agent_radius %s can stand on."
254
+ (
255
+ "The geometry read gave no floor an agent of agent_height %s and agent_radius %s can "
256
+ + "stand on."
257
+ )
239
258
  % [mesh.agent_height, mesh.agent_radius]
240
259
  )
241
260
 
@@ -252,7 +271,7 @@ static func _nothing_read(scene: GdhSceneFile, held: Resource) -> String:
252
271
  )
253
272
  % [
254
273
  _source_said(polygon.source_geometry_mode, polygon.source_geometry_group_name),
255
- polygon.agent_radius
274
+ polygon.agent_radius,
256
275
  ]
257
276
  )
258
277
  var outside: PackedStringArray = []
@@ -270,8 +289,9 @@ static func _nothing_read(scene: GdhSceneFile, held: Resource) -> String:
270
289
  return said
271
290
  return (
272
291
  (
273
- "%s %s %s outside what was read; the bake reads a node elsewhere once it is in the group %s and "
274
- + "source_geometry_mode is groups_with_children, or once it is moved under the region."
292
+ "%s %s %s outside what was read; the bake reads a node elsewhere once it is in the "
293
+ + "group %s and source_geometry_mode is groups_with_children, or once it is moved "
294
+ + "under the region."
275
295
  )
276
296
  % [
277
297
  said,
@@ -1,6 +1,5 @@
1
1
  @tool
2
2
  extends Node
3
-
4
3
  ## Running the game from the editor, so the editor is the one debugging it.
5
4
  ##
6
5
  ## A game started as its own process is a game nothing is attached to: the editor's debug adapter
@@ -10,7 +9,6 @@ extends Node
10
9
 
11
10
  ## What the display server calls itself when the engine was started with no display at all.
12
11
  const GdhRead = preload("../reading.gd")
13
-
14
12
  const HEADLESS_DISPLAY: String = "headless"
15
13
  ## Where Godot keeps the port its own debugger listens on for a game it is playing. One setting
16
14
  ## for every editor on the machine, and bound only while a game runs.
@@ -18,7 +16,6 @@ const DEBUGGER_SETTING: String = "network/debug/remote_port"
18
16
  const LOOPBACK: String = "127.0.0.1"
19
17
 
20
18
  var _editor_plugin: EditorPlugin = null
21
-
22
19
  ## Which play this is, counted up for every one the editor starts, whoever starts it. What a server
23
20
  ## writes about a play is kept on disk after it, and the editor saying it is playing does not say
24
21
  ## which play: a server picking a play back up read the console of an earlier one as this one's.
@@ -29,14 +26,14 @@ var _was_playing: bool = false
29
26
  var _awaited: bool = false
30
27
 
31
28
 
32
- func set_editor_plugin(plugin: EditorPlugin) -> void:
33
- _editor_plugin = plugin
34
-
35
-
36
29
  func _process(_delta: float) -> void:
37
30
  _count_a_play_begun()
38
31
 
39
32
 
33
+ func set_editor_plugin(plugin: EditorPlugin) -> void:
34
+ _editor_plugin = plugin
35
+
36
+
40
37
  ## Counts a play the editor has begun since the last look, whoever began it. Looked at every frame
41
38
  ## and before the count is read: read alone, a play begun in this frame went uncounted until this
42
39
  ## node's turn came round, and a server asking before then was told the earlier play's number with
@@ -60,20 +57,23 @@ func play_scene(args: Dictionary) -> Dictionary:
60
57
  # play was answered as started.
61
58
  var main: String = str(ProjectSettings.get_setting("application/run/main_scene", ""))
62
59
  if main.is_empty():
63
- return {"ok": false, "error": "The project has no main scene to play."}
60
+ return { "ok": false, "error": "The project has no main scene to play." }
64
61
  if not ResourceLoader.exists(main, "PackedScene"):
65
62
  return {
66
63
  "ok": false,
67
64
  "error":
68
65
  (
69
- "The main scene, %s, is not there, so the editor would ask for another rather than play."
66
+ (
67
+ "The main scene, %s, is not there, so the editor would ask for another "
68
+ + "rather than play."
69
+ )
70
70
  % main
71
- )
71
+ ),
72
72
  }
73
73
  else:
74
74
  full_path = scene_path if scene_path.begins_with("res://") else "res://" + scene_path
75
75
  if not ResourceLoader.exists(full_path, "PackedScene"):
76
- return {"ok": false, "error": "No scene at " + full_path}
76
+ return { "ok": false, "error": "No scene at " + full_path }
77
77
 
78
78
  if EditorInterface.is_playing_scene():
79
79
  EditorInterface.stop_playing_scene()
@@ -138,7 +138,7 @@ func stop_playing(_args: Dictionary) -> Dictionary:
138
138
  # Known over now rather than at the next frame's look: a play somebody else starts before that
139
139
  # look would otherwise be read as this one still going, and given its number and its console.
140
140
  _was_playing = EditorInterface.is_playing_scene()
141
- return {"ok": true, "wasPlaying": was_playing, "playing": _was_playing}
141
+ return { "ok": true, "wasPlaying": was_playing, "playing": _was_playing }
142
142
 
143
143
 
144
144
  ## Restarts the editor, which is how a replaced addon is picked up.
@@ -167,7 +167,7 @@ func restart_editor(_args: Dictionary) -> Dictionary:
167
167
  "This editor is headless, and the engine does not hand back the arguments it was "
168
168
  + "started with, so nothing can bring it back as the editor it is. Start it again "
169
169
  + "yourself."
170
- )
170
+ ),
171
171
  }
172
172
 
173
173
  var saving: Dictionary = _save_everything()
@@ -177,7 +177,7 @@ func restart_editor(_args: Dictionary) -> Dictionary:
177
177
  # Deferred so this answer is on its way out before the editor goes.
178
178
  EditorInterface.restart_editor.call_deferred(true)
179
179
 
180
- return {"ok": true, "restarting": true, "saved": saving["saved"]}
180
+ return { "ok": true, "restarting": true, "saved": saving["saved"] }
181
181
 
182
182
 
183
183
  ## Saves every open scene, answering a refusal naming what is still unsaved, or the scenes that had
@@ -193,7 +193,7 @@ static func _save_everything() -> Dictionary:
193
193
  EditorInterface.save_all_scenes()
194
194
  var left: PackedStringArray = EditorInterface.get_unsaved_scenes()
195
195
  if left.is_empty():
196
- return {"ok": true, "saved": changed}
196
+ return { "ok": true, "saved": changed }
197
197
  var named: Array[String] = []
198
198
  for scene: String in left:
199
199
  named.append(scene if not scene.is_empty() else "a scene that has never been saved")
@@ -202,15 +202,15 @@ static func _save_everything() -> Dictionary:
202
202
  "error":
203
203
  (
204
204
  (
205
- "%s still %s unsaved changes after saving, and ending the editor would lose them. Save "
206
- + "or close %s in the editor first."
205
+ "%s still %s unsaved changes after saving, and ending the editor would lose them. "
206
+ + "Save or close %s in the editor first."
207
207
  )
208
208
  % [
209
209
  ", ".join(PackedStringArray(named)),
210
210
  "has" if named.size() == 1 else "have",
211
- "it" if named.size() == 1 else "them"
211
+ "it" if named.size() == 1 else "them",
212
212
  ]
213
- )
213
+ ),
214
214
  }
215
215
 
216
216
 
@@ -230,7 +230,7 @@ func quit_editor(_args: Dictionary) -> Dictionary:
230
230
  # Deferred so this answer is on its way out before the editor goes.
231
231
  _leave.call_deferred()
232
232
 
233
- return {"ok": true, "quitting": true, "saved": saving["saved"]}
233
+ return { "ok": true, "quitting": true, "saved": saving["saved"] }
234
234
 
235
235
 
236
236
  ## What the editor said as it started each of its servers, and the debug adapter started again when
@@ -258,7 +258,12 @@ func editor_servers(args: Dictionary) -> Dictionary:
258
258
  parent.add_child(adapter)
259
259
  parent.move_child(adapter, at)
260
260
  rebound = true
261
- return {"ok": true, "said": said, "rebound": rebound, "saidSince": _servers_said().slice(said.size())}
261
+ return {
262
+ "ok": true,
263
+ "said": said,
264
+ "rebound": rebound,
265
+ "saidSince": _servers_said().slice(said.size()),
266
+ }
262
267
 
263
268
 
264
269
  ## The lines the editor's log panel holds about its language server and debug adapter, in order.