gdharness 1.3.42 → 1.3.44
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.
- package/build/cli.js +383 -243
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +55 -33
- package/build/godot/addons/gdharness_editor/bridge_client.gd +53 -58
- package/build/godot/addons/gdharness_editor/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_editor/file_reads.gd +83 -42
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +68 -44
- package/build/godot/addons/gdharness_editor/plugin.gd +2 -3
- package/build/godot/addons/gdharness_editor/property_paths.gd +22 -12
- package/build/godot/addons/gdharness_editor/property_values.gd +143 -78
- package/build/godot/addons/gdharness_editor/reading.gd +51 -17
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +127 -80
- package/build/godot/addons/gdharness_editor/scene_uids.gd +12 -6
- package/build/godot/addons/gdharness_editor/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_editor/setting_reads.gd +7 -6
- package/build/godot/addons/gdharness_editor/tool_executor.gd +3 -6
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +37 -27
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +79 -49
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +65 -42
- package/build/godot/addons/gdharness_editor/tools/filesystem_tools.gd +24 -22
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +49 -29
- package/build/godot/addons/gdharness_editor/tools/play_tools.gd +26 -21
- package/build/godot/addons/gdharness_editor/tools/profile_tools.gd +40 -40
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +166 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +68 -41
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +35 -20
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +28 -13
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd +12 -5
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +113 -67
- package/build/godot/addons/gdharness_editor/tools/script_paths.gd +20 -8
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +11 -8
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +47 -34
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +77 -50
- package/build/godot/addons/gdharness_editor/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_runtime/call_errors.gd +1 -2
- package/build/godot/addons/gdharness_runtime/declared_values.gd +68 -32
- package/build/godot/addons/gdharness_runtime/error_report.gd +1 -2
- package/build/godot/addons/gdharness_runtime/reading.gd +51 -17
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +149 -147
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +64 -42
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +184 -122
- package/build/godot/addons/gdharness_runtime/runtime_frames.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_hover.gd +24 -20
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +134 -92
- package/build/godot/addons/gdharness_runtime/runtime_items.gd +29 -13
- package/build/godot/addons/gdharness_runtime/runtime_menus.gd +0 -1
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +34 -17
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +17 -13
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +84 -46
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +117 -79
- package/build/godot/addons/gdharness_runtime/runtime_says.gd +14 -17
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +23 -16
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +117 -66
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd +15 -15
- package/build/godot/addons/gdharness_runtime/runtime_typing.gd +44 -27
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +108 -73
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +111 -84
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +10 -7
- package/build/godot/addons/gdharness_runtime/serialisation.gd +75 -51
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +5 -6
- package/build/godot/addons/gdharness_tests/bench.gd +4 -5
- package/build/godot/addons/gdharness_tests/event.gd +10 -5
- package/build/godot/addons/gdharness_tests/share.gd +38 -18
- package/build/godot/addons/gdharness_tests/suites.gd +3 -3
- package/build/godot/addons/gdharness_tests/wait.gd +3 -2
- package/build/godot/loader/loader.gd +9 -9
- package/build/godot/operations/animation_reads.gd +55 -33
- package/build/godot/operations/audio_buses.gd +48 -19
- package/build/godot/operations/class_cache.gd +16 -11
- package/build/godot/operations/classdb_queries.gd +89 -44
- package/build/godot/operations/declared_values.gd +68 -32
- package/build/godot/operations/dependencies.gd +190 -109
- package/build/godot/operations/editor_tools.gd +10 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +83 -42
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +86 -65
- package/build/godot/operations/gdscript_authoring.gd +83 -36
- package/build/godot/operations/godot_operations.gd +17 -11
- package/build/godot/operations/import_pipeline.gd +110 -59
- package/build/godot/operations/input_actions.gd +62 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +61 -32
- package/build/godot/operations/project_diagnostics.gd +24 -11
- package/build/godot/operations/project_file.gd +16 -16
- package/build/godot/operations/project_validation.gd +71 -44
- package/build/godot/operations/property_paths.gd +22 -12
- package/build/godot/operations/property_values.gd +143 -78
- package/build/godot/operations/reading.gd +51 -17
- package/build/godot/operations/rename_checks.gd +2 -2
- package/build/godot/operations/resource_files.gd +11 -9
- package/build/godot/operations/same_values.gd +4 -4
- package/build/godot/operations/scene_connections.gd +27 -13
- package/build/godot/operations/script_check.gd +52 -49
- package/build/godot/operations/serialisation.gd +75 -51
- package/build/godot/operations/setting_reads.gd +7 -6
- package/build/godot/operations/value_shapes.gd +5 -6
- package/build/godot/tests/listed.gd +321 -268
- package/build/keeper.js +43 -43
- package/package.json +1 -1
|
@@ -5,13 +5,14 @@ const GdhRead = preload("reading.gd")
|
|
|
5
5
|
const GdhLog = preload("logger.gd")
|
|
6
6
|
const GdhPatterns = preload("patterns.gd")
|
|
7
7
|
const GdhScriptCheck = preload("script_check.gd")
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const MODIFICATION_TYPES: Array[String] = [
|
|
9
|
+
"add_constant", "add_variable", "add_signal", "add_function",
|
|
10
|
+
]
|
|
10
11
|
## The class each template's code is written for, and the base a script made from it extends
|
|
11
12
|
## when given none: the resource template's code is a Resource's, and on the default of Node it
|
|
12
13
|
## does not parse.
|
|
13
14
|
const TEMPLATE_BASES: Dictionary = {
|
|
14
|
-
"singleton": "Node", "state_machine": "Node", "component": "Node", "resource": "Resource"
|
|
15
|
+
"singleton": "Node", "state_machine": "Node", "component": "Node", "resource": "Resource",
|
|
15
16
|
}
|
|
16
17
|
const BLANKS_AROUND_FUNCTIONS: int = 2
|
|
17
18
|
|
|
@@ -35,7 +36,8 @@ func create_gdscript(params: Dictionary) -> Dictionary:
|
|
|
35
36
|
_log.info("Creating GDScript: " + script_path)
|
|
36
37
|
|
|
37
38
|
# Content is the whole file, so a header written above it would be a second one: a content that
|
|
38
|
-
# starts with its own `extends` did not parse, and one without it was not the file that was
|
|
39
|
+
# starts with its own `extends` did not parse, and one without it was not the file that was
|
|
40
|
+
# sent.
|
|
39
41
|
if not content.is_empty():
|
|
40
42
|
var alongside: Array[String] = []
|
|
41
43
|
for name: String in ["class_name", "extends", "template"]:
|
|
@@ -64,8 +66,8 @@ func create_gdscript(params: Dictionary) -> Dictionary:
|
|
|
64
66
|
"Script file already exists: " + full_script_path + ". script_edit modify adds to it."
|
|
65
67
|
)
|
|
66
68
|
|
|
67
|
-
# Content is left to the parse below: two scripts that name each other are written one at a
|
|
68
|
-
# and the first does not compile until the second exists.
|
|
69
|
+
# Content is left to the parse below: two scripts that name each other are written one at a
|
|
70
|
+
# time, and the first does not compile until the second exists.
|
|
69
71
|
if content.is_empty():
|
|
70
72
|
var header: String = _header_refusal(cls_name_param, extends_class)
|
|
71
73
|
if header.is_empty() and not template.is_empty():
|
|
@@ -79,7 +81,9 @@ func create_gdscript(params: Dictionary) -> Dictionary:
|
|
|
79
81
|
_log.debug("Creating directory: " + script_dir)
|
|
80
82
|
var error: Error = dir.make_dir_recursive(script_dir.substr(6))
|
|
81
83
|
if error != OK:
|
|
82
|
-
return _log.failure(
|
|
84
|
+
return _log.failure(
|
|
85
|
+
"Failed to create directory: " + script_dir + ", error: " + str(error)
|
|
86
|
+
)
|
|
83
87
|
|
|
84
88
|
var script_content: String = content
|
|
85
89
|
if content.is_empty():
|
|
@@ -104,7 +108,9 @@ func create_gdscript(params: Dictionary) -> Dictionary:
|
|
|
104
108
|
# project is imported, so a script made here was missing from every check tracking the sidecars.
|
|
105
109
|
var uid: String = _uid_beside(full_script_path)
|
|
106
110
|
|
|
107
|
-
var written: Script = ResourceLoader.load(
|
|
111
|
+
var written: Script = ResourceLoader.load(
|
|
112
|
+
full_script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE
|
|
113
|
+
)
|
|
108
114
|
var parses: bool = _parses(written)
|
|
109
115
|
var answer: Dictionary = {
|
|
110
116
|
"success": true,
|
|
@@ -162,7 +168,7 @@ static func _not_gdscript(path: String, doing: String) -> String:
|
|
|
162
168
|
## extends extends RefCounted, and one with no class_name answers null for it, as an absent name
|
|
163
169
|
## does everywhere else rather than as a name that is empty.
|
|
164
170
|
static func _header_written(text: String) -> Dictionary:
|
|
165
|
-
var header: Dictionary = {"extends": "RefCounted", "class_name": null}
|
|
171
|
+
var header: Dictionary = { "extends": "RefCounted", "class_name": null }
|
|
166
172
|
for line: String in text.split("\n"):
|
|
167
173
|
# An inner class's extends is indented, and is not the script's.
|
|
168
174
|
if line.begins_with(" ") or line.begins_with("\t"):
|
|
@@ -208,15 +214,18 @@ func modify_gdscript(params: Dictionary) -> Dictionary:
|
|
|
208
214
|
|
|
209
215
|
var lines: Array[String] = []
|
|
210
216
|
lines.assign(original_content.split("\n"))
|
|
211
|
-
# Loaded only to learn whether it parsed as it was. What the engine says of that file carries
|
|
212
|
-
# old line numbers, and beside the errors of the file written it named lines that had moved.
|
|
217
|
+
# Loaded only to learn whether it parsed as it was. What the engine says of that file carries
|
|
218
|
+
# its old line numbers, and beside the errors of the file written it named lines that had moved.
|
|
213
219
|
printerr(GdhLog.ASIDE)
|
|
214
|
-
var before: Script = ResourceLoader.load(
|
|
220
|
+
var before: Script = ResourceLoader.load(
|
|
221
|
+
full_script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE
|
|
222
|
+
)
|
|
215
223
|
printerr(GdhLog.RESUMED)
|
|
216
224
|
var parsed_before: bool = _parses(before)
|
|
217
225
|
|
|
218
|
-
# All of them checked before any is made, so a call is made whole or not at all: one skipped for
|
|
219
|
-
# missing name used to leave the rest written and the answer saying success over an empty
|
|
226
|
+
# All of them checked before any is made, so a call is made whole or not at all: one skipped for
|
|
227
|
+
# a missing name used to leave the rest written and the answer saying success over an empty
|
|
228
|
+
# list.
|
|
220
229
|
var declared: Dictionary = _declared(lines)
|
|
221
230
|
var problems: Array[String] = _modification_problems(modifications, declared)
|
|
222
231
|
if not problems.is_empty():
|
|
@@ -247,14 +256,22 @@ func modify_gdscript(params: Dictionary) -> Dictionary:
|
|
|
247
256
|
at = _add_function(lines, fields, placed)
|
|
248
257
|
if at == -1:
|
|
249
258
|
return _log.failure(
|
|
250
|
-
|
|
259
|
+
(
|
|
260
|
+
"Nothing was changed: "
|
|
261
|
+
+ mod_type
|
|
262
|
+
+ " "
|
|
263
|
+
+ str(fields.get("name"))
|
|
264
|
+
+ " could not be placed"
|
|
265
|
+
)
|
|
251
266
|
)
|
|
252
|
-
placed.append({"type": mod_type, "name": str(fields.get("name")), "index": at})
|
|
267
|
+
placed.append({ "type": mod_type, "name": str(fields.get("name")), "index": at })
|
|
253
268
|
|
|
254
269
|
var modifications_applied: Array[Dictionary] = []
|
|
255
270
|
for entry: Dictionary in placed:
|
|
256
271
|
var index: int = entry["index"]
|
|
257
|
-
modifications_applied.append(
|
|
272
|
+
modifications_applied.append(
|
|
273
|
+
{ "type": entry["type"], "name": entry["name"], "line": index + 1 }
|
|
274
|
+
)
|
|
258
275
|
|
|
259
276
|
file = FileAccess.open(full_script_path, FileAccess.WRITE)
|
|
260
277
|
if not file:
|
|
@@ -267,7 +284,9 @@ func modify_gdscript(params: Dictionary) -> Dictionary:
|
|
|
267
284
|
|
|
268
285
|
var caught: GdhScriptCheck.GdhCaught = GdhScriptCheck.GdhCaught.new()
|
|
269
286
|
OS.add_logger(caught)
|
|
270
|
-
var made: Script = ResourceLoader.load(
|
|
287
|
+
var made: Script = ResourceLoader.load(
|
|
288
|
+
full_script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE
|
|
289
|
+
)
|
|
271
290
|
OS.remove_logger(caught)
|
|
272
291
|
var parses: bool = _parses(made)
|
|
273
292
|
# The names checked above are the script's own, and a member the base class declares, or a body
|
|
@@ -281,7 +300,10 @@ func modify_gdscript(params: Dictionary) -> Dictionary:
|
|
|
281
300
|
file.close()
|
|
282
301
|
if not restored:
|
|
283
302
|
return _log.failure(
|
|
284
|
-
|
|
303
|
+
(
|
|
304
|
+
"%s would not parse with these additions, and could not be put back as it was"
|
|
305
|
+
% script_path
|
|
306
|
+
)
|
|
285
307
|
)
|
|
286
308
|
return _log.failure(
|
|
287
309
|
(
|
|
@@ -319,12 +341,15 @@ static func _header_refusal(named: String, base: String) -> String:
|
|
|
319
341
|
var declared: Dictionary = _declared_classes()
|
|
320
342
|
if not named.is_empty():
|
|
321
343
|
if ClassDB.class_exists(named):
|
|
322
|
-
return
|
|
344
|
+
return (
|
|
345
|
+
"class_name %s is the name of an engine class, which a script cannot take." % named
|
|
346
|
+
)
|
|
323
347
|
if declared.has(named):
|
|
324
348
|
return (
|
|
325
349
|
(
|
|
326
|
-
"class_name %s is taken: %s declares it, and a second script of that name does
|
|
327
|
-
+ "compile. Give this one another class_name, or script_edit rename the
|
|
350
|
+
"class_name %s is taken: %s declares it, and a second script of that name does "
|
|
351
|
+
+ "not compile. Give this one another class_name, or script_edit rename the "
|
|
352
|
+
+ "first."
|
|
328
353
|
)
|
|
329
354
|
% [named, declared[named]]
|
|
330
355
|
)
|
|
@@ -333,7 +358,8 @@ static func _header_refusal(named: String, base: String) -> String:
|
|
|
333
358
|
if ClassDB.class_exists(base) or declared.has(base):
|
|
334
359
|
return ""
|
|
335
360
|
var said: String = (
|
|
336
|
-
"extends names %s, which is neither an engine class nor a class_name this project declares"
|
|
361
|
+
"extends names %s, which is neither an engine class nor a class_name this project declares"
|
|
362
|
+
% base
|
|
337
363
|
)
|
|
338
364
|
var close: PackedStringArray = GdhRead.nearest(base, PackedStringArray(declared.keys()))
|
|
339
365
|
if close.is_empty():
|
|
@@ -390,7 +416,9 @@ static func _declared_classes() -> Dictionary:
|
|
|
390
416
|
declared[str(entry.get("class", ""))] = path
|
|
391
417
|
for path: String in GdhFileWalk.new().find_files("res://", ".gd"):
|
|
392
418
|
for line: String in FileAccess.get_file_as_string(path).split("\n"):
|
|
393
|
-
var found: RegExMatch = GdhPatterns.declared_class(
|
|
419
|
+
var found: RegExMatch = GdhPatterns.declared_class(
|
|
420
|
+
GdhPatterns.without_annotations(line)
|
|
421
|
+
)
|
|
394
422
|
if found != null and not declared.has(found.get_string(1)):
|
|
395
423
|
declared[found.get_string(1)] = path
|
|
396
424
|
return declared
|
|
@@ -425,20 +453,31 @@ static func _modification_problems(modifications: Array, declared: Dictionary) -
|
|
|
425
453
|
)
|
|
426
454
|
)
|
|
427
455
|
if mod_type == "add_constant" and str(fields.get("defaultValue", "")).is_empty():
|
|
428
|
-
problems.append(
|
|
456
|
+
problems.append(
|
|
457
|
+
which + " is a constant with no defaultValue, and a constant needs a value"
|
|
458
|
+
)
|
|
429
459
|
if (
|
|
430
460
|
not str(fields.get("exportHint", "")).is_empty()
|
|
431
461
|
and fields.has("isExport")
|
|
432
462
|
and not GdhRead.as_bool(fields["isExport"])
|
|
433
463
|
):
|
|
434
|
-
|
|
435
|
-
|
|
464
|
+
(
|
|
465
|
+
problems
|
|
466
|
+
. append(
|
|
467
|
+
(
|
|
468
|
+
which
|
|
469
|
+
+ " has an exportHint and isExport false, and a hint is written only on an "
|
|
470
|
+
+ "export"
|
|
471
|
+
)
|
|
472
|
+
)
|
|
436
473
|
)
|
|
437
474
|
if mod_name.is_empty():
|
|
438
475
|
problems.append(which + " has no name")
|
|
439
476
|
continue
|
|
440
477
|
if not mod_name.is_valid_unicode_identifier():
|
|
441
|
-
problems.append(
|
|
478
|
+
problems.append(
|
|
479
|
+
which + " is named '" + mod_name + "', which GDScript does not accept as a name"
|
|
480
|
+
)
|
|
442
481
|
continue
|
|
443
482
|
if declared.has(mod_name):
|
|
444
483
|
var existing: Dictionary = declared[mod_name]
|
|
@@ -449,7 +488,9 @@ static func _modification_problems(modifications: Array, declared: Dictionary) -
|
|
|
449
488
|
)
|
|
450
489
|
)
|
|
451
490
|
elif added.has(mod_name):
|
|
452
|
-
problems.append(
|
|
491
|
+
problems.append(
|
|
492
|
+
"%s adds %s, which modification %d adds too" % [which, mod_name, added[mod_name]]
|
|
493
|
+
)
|
|
453
494
|
else:
|
|
454
495
|
added[mod_name] = index + 1
|
|
455
496
|
return problems
|
|
@@ -477,11 +518,12 @@ static func _declared(lines: Array[String]) -> Dictionary:
|
|
|
477
518
|
continue
|
|
478
519
|
var matched: RegExMatch = declaration.search(GdhPatterns.without_annotations(raw))
|
|
479
520
|
if matched != null and not found.has(matched.get_string(2)):
|
|
480
|
-
found[matched.get_string(2)] = {"kind": matched.get_string(1), "line": i + 1}
|
|
521
|
+
found[matched.get_string(2)] = { "kind": matched.get_string(1), "line": i + 1 }
|
|
481
522
|
return found
|
|
482
523
|
|
|
483
524
|
|
|
484
|
-
# Inserts [param new_lines] at [param at] and moves every placed line at or below it down by as
|
|
525
|
+
# Inserts [param new_lines] at [param at] and moves every placed line at or below it down by as
|
|
526
|
+
# many.
|
|
485
527
|
static func _insert(
|
|
486
528
|
lines: Array[String], at: int, new_lines: Array[String], placed: Array[Dictionary]
|
|
487
529
|
) -> bool:
|
|
@@ -552,7 +594,8 @@ func _add_constant(lines: Array[String], mod: Dictionary, placed: Array[Dictiona
|
|
|
552
594
|
return after + block.find(const_line) if _insert(lines, after, block, placed) else -1
|
|
553
595
|
|
|
554
596
|
|
|
555
|
-
# Inserts the declaration and answers with its zero-based index, or -1 for one that could not be
|
|
597
|
+
# Inserts the declaration and answers with its zero-based index, or -1 for one that could not be
|
|
598
|
+
# placed.
|
|
556
599
|
func _add_variable(lines: Array[String], mod: Dictionary, placed: Array[Dictionary]) -> int:
|
|
557
600
|
var var_name: String = str(mod.get("name", ""))
|
|
558
601
|
var var_type: String = str(mod.get("varType", ""))
|
|
@@ -639,7 +682,7 @@ func _add_signal(lines: Array[String], mod: Dictionary, placed: Array[Dictionary
|
|
|
639
682
|
# Answers with the zero-based index of the `func` line, below the blank lines that separate it.
|
|
640
683
|
#
|
|
641
684
|
# Two blank lines on each side, counting those already there, because that is the spacing GDScript's
|
|
642
|
-
# style guide gives functions and the one
|
|
685
|
+
# style guide gives functions and the one gdstyle and gdformat write: one blank line passed
|
|
643
686
|
# the engine and failed every project gating on either. A function last in the file ends it with a
|
|
644
687
|
# newline, which the file is written with only when its last line is empty.
|
|
645
688
|
func _add_function(lines: Array[String], mod: Dictionary, placed: Array[Dictionary]) -> int:
|
|
@@ -803,9 +846,9 @@ func _line_after_function(lines: Array[String], prefix: String) -> int:
|
|
|
803
846
|
|
|
804
847
|
|
|
805
848
|
# The first line belonging to the declaration on [param at]: the comments and the lines holding only
|
|
806
|
-
# annotations directly above it, at its indentation. A function placed on [param at] itself takes
|
|
807
|
-
# next function's doc comment, which then documents the wrong one, and its `@rpc` line, which
|
|
808
|
-
# annotates it. A comment indented further is the end of the body above, and stays with it.
|
|
849
|
+
# annotations directly above it, at its indentation. A function placed on [param at] itself takes
|
|
850
|
+
# the next function's doc comment, which then documents the wrong one, and its `@rpc` line, which
|
|
851
|
+
# then annotates it. A comment indented further is the end of the body above, and stays with it.
|
|
809
852
|
static func _start_of_declaration(lines: Array[String], at: int) -> int:
|
|
810
853
|
var indent: String = _indentation(lines[at])
|
|
811
854
|
var start: int = at
|
|
@@ -835,6 +878,8 @@ func _ready() -> void:
|
|
|
835
878
|
\tpass
|
|
836
879
|
"""
|
|
837
880
|
"state_machine":
|
|
881
|
+
# The made script's first line, which is under the limit in the file it is written to.
|
|
882
|
+
# gdstyle:ignore=format/max-line-length
|
|
838
883
|
return """## A finite state machine: one state at a time, entered and left through change_state.
|
|
839
884
|
|
|
840
885
|
signal state_changed(old_state: String, new_state: String)
|
|
@@ -886,6 +931,7 @@ func _call_state(state_name: String, method: String, args: Array) -> void:
|
|
|
886
931
|
\t\tstate.callv(method, args)
|
|
887
932
|
"""
|
|
888
933
|
"component":
|
|
934
|
+
# gdstyle:ignore=format/max-line-length
|
|
889
935
|
return """## A component: a child node that adds one behaviour to its parent, switched off with disable().
|
|
890
936
|
|
|
891
937
|
@export var enabled: bool = true
|
|
@@ -916,6 +962,7 @@ func disable() -> void:
|
|
|
916
962
|
\tset_physics_process(false)
|
|
917
963
|
"""
|
|
918
964
|
"resource":
|
|
965
|
+
# gdstyle:ignore=format/max-line-length
|
|
919
966
|
return """## Data kept in a .tres file, which resource_edit create makes and the game loads.
|
|
920
967
|
|
|
921
968
|
@export var id: String = ""
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env -S godot --headless --script
|
|
2
2
|
extends SceneTree
|
|
3
3
|
|
|
4
|
-
# The command line the server runs is
|
|
5
|
-
# <operation> @file:<params.json> <answer.json>`,
|
|
6
|
-
# file is the answer. Everything an operation does
|
|
7
|
-
# command table and the wire format.
|
|
4
|
+
# The command line the server runs is
|
|
5
|
+
# `godot --headless --path <project> --script <this> <operation> @file:<params.json> <answer.json>`,
|
|
6
|
+
# and the one JSON object written to the answer file is the answer. Everything an operation does
|
|
7
|
+
# lives in a sibling module; this file is the command table and the wire format.
|
|
8
8
|
#
|
|
9
9
|
# A file rather than a line on stdout, because the project's autoloads run after `_init` and print
|
|
10
10
|
# into the same stream: an autoload printing a dictionary in `_process` was the last JSON line out
|
|
@@ -34,17 +34,14 @@ const GdhRead = preload("reading.gd")
|
|
|
34
34
|
const GdhRenameChecks = preload("rename_checks.gd")
|
|
35
35
|
const GdhResourceFiles = preload("resource_files.gd")
|
|
36
36
|
const GdhScriptCheck = preload("script_check.gd")
|
|
37
|
-
|
|
38
37
|
## Printed once the answer is written, after which the engine runs the project's autoloads. Kept in
|
|
39
38
|
## step with `ANSWERED` in src/headless.ts.
|
|
40
39
|
const ANSWERED: String = "[gdharness] answered"
|
|
41
|
-
|
|
42
40
|
## Printed in `_init` by an operation that runs once the project's autoloads are in the tree, and
|
|
43
41
|
## when it begins there. Kept in step with `WAITING` and `BEGUN` in src/headless.ts, which files
|
|
44
42
|
## what the autoloads print in between as theirs rather than the operation's.
|
|
45
43
|
const WAITING: String = "[gdharness] waiting for the autoloads"
|
|
46
44
|
const BEGUN: String = "[gdharness] begun"
|
|
47
|
-
|
|
48
45
|
## The operations that compile the project's scripts. The engine knows an autoload's name only once
|
|
49
46
|
## the autoload is in the tree, which is after `_init`, so a script naming one compiled here failed
|
|
50
47
|
## with "Identifier not found" while the game and the editor ran it. A scene tool, and a read of a
|
|
@@ -116,7 +113,9 @@ func _init() -> void:
|
|
|
116
113
|
_answer(operation, params, answer_path)
|
|
117
114
|
|
|
118
115
|
|
|
119
|
-
func _answer_after_the_autoloads(
|
|
116
|
+
func _answer_after_the_autoloads(
|
|
117
|
+
operation: String, params: Dictionary, answer_path: String
|
|
118
|
+
) -> void:
|
|
120
119
|
printerr(BEGUN)
|
|
121
120
|
_answer(operation, params, answer_path)
|
|
122
121
|
|
|
@@ -131,7 +130,12 @@ func _answer(operation: String, params: Dictionary, answer_path: String) -> void
|
|
|
131
130
|
var answer: FileAccess = FileAccess.open(answer_path, FileAccess.WRITE)
|
|
132
131
|
if answer == null:
|
|
133
132
|
_log.error(
|
|
134
|
-
|
|
133
|
+
(
|
|
134
|
+
"Could not write the answer to "
|
|
135
|
+
+ answer_path
|
|
136
|
+
+ ": "
|
|
137
|
+
+ error_string(FileAccess.get_open_error())
|
|
138
|
+
)
|
|
135
139
|
)
|
|
136
140
|
quit(1)
|
|
137
141
|
return
|
|
@@ -168,7 +172,9 @@ func _read_params(argument: String) -> Variant:
|
|
|
168
172
|
var json: JSON = JSON.new()
|
|
169
173
|
if json.parse(params_json) != OK:
|
|
170
174
|
_log.error("Failed to parse JSON parameters: " + params_json)
|
|
171
|
-
_log.error(
|
|
175
|
+
_log.error(
|
|
176
|
+
"JSON Error: " + json.get_error_message() + " at line " + str(json.get_error_line())
|
|
177
|
+
)
|
|
172
178
|
return null
|
|
173
179
|
|
|
174
180
|
var params: Variant = json.get_data()
|
|
@@ -338,7 +344,7 @@ func _editor_tool(params: Dictionary) -> Dictionary:
|
|
|
338
344
|
var path: String = own.resource_path.get_base_dir().path_join("editor_tools.gd")
|
|
339
345
|
var tools: Script = ResourceLoader.load(path, "Script")
|
|
340
346
|
if tools == null or not tools.can_instantiate():
|
|
341
|
-
return {"ok": false, "error": "The editor tools did not load from %s." % path}
|
|
347
|
+
return { "ok": false, "error": "The editor tools did not load from %s." % path }
|
|
342
348
|
var answer: Dictionary = tools.call("run", params)
|
|
343
349
|
return answer
|
|
344
350
|
|