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.
- package/build/cli.js +131 -47
- package/build/godot/addons/auto_reload/auto_reload.gd +18 -19
- package/build/godot/addons/gdharness_editor/animation_reads.gd +84 -35
- 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 +114 -39
- package/build/godot/addons/gdharness_editor/file_walk.gd +12 -5
- package/build/godot/addons/gdharness_editor/headless_check.gd +94 -41
- 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 +37 -12
- package/build/godot/addons/gdharness_editor/same_values.gd +4 -4
- package/build/godot/addons/gdharness_editor/scene_file.gd +136 -79
- 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 +41 -28
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +84 -50
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +70 -40
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +34 -30
- 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 +181 -107
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +75 -43
- 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 +66 -0
- package/build/godot/addons/gdharness_editor/tools/scene_sharing.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +171 -62
- 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 +37 -12
- package/build/godot/addons/gdharness_runtime/runtime_accessibility.gd +84 -63
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +153 -148
- 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 +38 -20
- 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 +211 -0
- package/build/godot/addons/gdharness_runtime/runtime_touch.gd.uid +1 -0
- 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 +84 -35
- 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 +139 -93
- package/build/godot/operations/editor_tools.gd +9 -10
- package/build/godot/operations/export_presets.gd +100 -54
- package/build/godot/operations/file_reads.gd +114 -39
- package/build/godot/operations/file_walk.gd +12 -5
- package/build/godot/operations/gdscript_analysis.gd +105 -66
- package/build/godot/operations/gdscript_authoring.gd +138 -39
- 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 +63 -39
- package/build/godot/operations/patterns.gd +3 -1
- package/build/godot/operations/plugins.gd +36 -16
- package/build/godot/operations/project_config.gd +144 -27
- 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 +37 -12
- 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/package.json +1 -1
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
@tool
|
|
2
2
|
extends Node
|
|
3
|
-
|
|
4
3
|
## Signal connections in a scene file, made, removed and listed on a copy of the file as the other
|
|
5
4
|
## scene tools edit one.
|
|
6
5
|
|
|
7
6
|
const GdhRead = preload("../reading.gd")
|
|
8
7
|
const GdhSceneFile = preload("../scene_file.gd")
|
|
9
8
|
const GdhSerialisation = preload("../serialisation.gd")
|
|
10
|
-
|
|
11
9
|
## What every emission meets when a connection cannot call its method.
|
|
12
10
|
const FAILS: String = ", so every emission fails to call it."
|
|
13
11
|
## The engine's CONNECT_INHERITED, which GDScript is not given: on a connection an instanced or
|
|
@@ -54,10 +52,10 @@ func connect_signal(args: Dictionary) -> Dictionary:
|
|
|
54
52
|
or target_node_path.is_empty()
|
|
55
53
|
or method_name.is_empty()
|
|
56
54
|
):
|
|
57
|
-
return {"ok": false, "error": "Missing required signal connection arguments"}
|
|
55
|
+
return { "ok": false, "error": "Missing required signal connection arguments" }
|
|
58
56
|
var unasked: String = _unasked(given_flags)
|
|
59
57
|
if not unasked.is_empty():
|
|
60
|
-
return {"ok": false, "error": unasked}
|
|
58
|
+
return { "ok": false, "error": unasked }
|
|
61
59
|
|
|
62
60
|
var scene: GdhSceneFile = GdhSceneFile.new()
|
|
63
61
|
var refused: Dictionary = scene.open(scene_path, true)
|
|
@@ -73,8 +71,8 @@ func connect_signal(args: Dictionary) -> Dictionary:
|
|
|
73
71
|
# Reconnected rather than left alone when the flags differ, so the connection saved is the one
|
|
74
72
|
# asked for. Left alone, the answer gave the flags asked for and the file kept the old ones.
|
|
75
73
|
# Found by its object and method, as the engine finds it: a connection carrying binds is another
|
|
76
|
-
# callable, so comparing callables missed it, and the engine's is_connected then found it, took
|
|
77
|
-
# out and put a bare one in its place, losing the binds without a word.
|
|
74
|
+
# callable, so comparing callables missed it, and the engine's is_connected then found it, took
|
|
75
|
+
# it out and put a bare one in its place, losing the binds without a word.
|
|
78
76
|
var before: Dictionary = _held(source, signal_name, target, method_name)
|
|
79
77
|
var binds: Array = []
|
|
80
78
|
var unbinds: int = 0
|
|
@@ -85,7 +83,9 @@ func connect_signal(args: Dictionary) -> Dictionary:
|
|
|
85
83
|
unbinds = GdhRead.as_int(args["unbinds"])
|
|
86
84
|
if args.has("binds"):
|
|
87
85
|
var given: Array = args["binds"]
|
|
88
|
-
binds = _bound_values(
|
|
86
|
+
binds = _bound_values(
|
|
87
|
+
given, source, signal_name, Callable(target, method_name), unbinds, flags
|
|
88
|
+
)
|
|
89
89
|
var callable: Callable = Callable(target, method_name)
|
|
90
90
|
if not binds.is_empty():
|
|
91
91
|
callable = callable.bindv(binds)
|
|
@@ -125,7 +125,7 @@ func connect_signal(args: Dictionary) -> Dictionary:
|
|
|
125
125
|
"flagNames": flag_names(saved_flags),
|
|
126
126
|
# Connected either way, as the editor's own dialog allows, since the method may be written
|
|
127
127
|
# next; a caller told nothing learnt of a misspelt one only when the signal fired.
|
|
128
|
-
"methodFound": method_found
|
|
128
|
+
"methodFound": method_found,
|
|
129
129
|
}
|
|
130
130
|
# Written all the same, for the reason a missing method is: the method may be changed next.
|
|
131
131
|
if method_found:
|
|
@@ -192,7 +192,9 @@ func _bound_values(
|
|
|
192
192
|
declared = GdhRead.as_int(parameter.get("type", TYPE_NIL))
|
|
193
193
|
if value is float and declared != TYPE_FLOAT:
|
|
194
194
|
var number: float = value
|
|
195
|
-
if is_finite(number)
|
|
195
|
+
if (is_finite(number)
|
|
196
|
+
and number == floorf(number)
|
|
197
|
+
and absf(number) < 9_007_199_254_740_992.0):
|
|
196
198
|
value = int(number)
|
|
197
199
|
values.append(value)
|
|
198
200
|
return values
|
|
@@ -244,9 +246,13 @@ func _connection_ends(
|
|
|
244
246
|
var source: Node = GdhSceneFile.node_at(scene.root, source_node_path)
|
|
245
247
|
var target: Node = GdhSceneFile.node_at(scene.root, target_node_path)
|
|
246
248
|
if not source:
|
|
247
|
-
return [
|
|
249
|
+
return [
|
|
250
|
+
null, scene.not_found("Source node not found: " + source_node_path, source_node_path),
|
|
251
|
+
]
|
|
248
252
|
if not target:
|
|
249
|
-
return [
|
|
253
|
+
return [
|
|
254
|
+
null, scene.not_found("Target node not found: " + target_node_path, target_node_path),
|
|
255
|
+
]
|
|
250
256
|
# pack drops a connection with either end inside an instanced scene, and the answer said it was
|
|
251
257
|
# made or removed.
|
|
252
258
|
for end: Node in [source, target]:
|
|
@@ -262,7 +268,9 @@ func _connection_ends(
|
|
|
262
268
|
|
|
263
269
|
## The persistent connection from [param from]'s [param signal_name] to [param method] on [param to]
|
|
264
270
|
## in the tree under [param root], as [method _held] answers it, or {} when there is none.
|
|
265
|
-
static func _saved(
|
|
271
|
+
static func _saved(
|
|
272
|
+
root: Node, from: String, signal_name: String, to: String, method: String
|
|
273
|
+
) -> Dictionary:
|
|
266
274
|
var source: Node = root.get_node_or_null(from)
|
|
267
275
|
var target: Node = root.get_node_or_null(to)
|
|
268
276
|
if source == null or target == null or not source.has_signal(signal_name):
|
|
@@ -273,11 +281,11 @@ static func _saved(root: Node, from: String, signal_name: String, to: String, me
|
|
|
273
281
|
return held
|
|
274
282
|
|
|
275
283
|
|
|
276
|
-
## Why what [param signal_name] of [param source] passes cannot reach [param callable], or "" when
|
|
277
|
-
## can or the method is not there to judge. Only what fails on every emission is named: too few
|
|
278
|
-
## too many arguments, an object passed where the method takes a value or the reverse, and an
|
|
279
|
-
## class unrelated to the one the method takes. Anything that may convert or narrow when it
|
|
280
|
-
## left alone, since a warning about a connection that works is one nobody can act on.
|
|
284
|
+
## Why what [param signal_name] of [param source] passes cannot reach [param callable], or "" when
|
|
285
|
+
## it can or the method is not there to judge. Only what fails on every emission is named: too few
|
|
286
|
+
## or too many arguments, an object passed where the method takes a value or the reverse, and an
|
|
287
|
+
## engine class unrelated to the one the method takes. Anything that may convert or narrow when it
|
|
288
|
+
## runs is left alone, since a warning about a connection that works is one nobody can act on.
|
|
281
289
|
static func _misfit(source: Node, signal_name: String, callable: Callable, flags: int) -> String:
|
|
282
290
|
var target: Object = callable.get_object()
|
|
283
291
|
var method: String = str(callable.get_method())
|
|
@@ -295,7 +303,7 @@ static func _misfit(source: Node, signal_name: String, callable: Callable, flags
|
|
|
295
303
|
passed.append(argument)
|
|
296
304
|
break
|
|
297
305
|
if flags & Object.CONNECT_APPEND_SOURCE_OBJECT:
|
|
298
|
-
passed.append({"name": "source", "type": TYPE_OBJECT, "class_name": source.get_class()})
|
|
306
|
+
passed.append({ "name": "source", "type": TYPE_OBJECT, "class_name": source.get_class() })
|
|
299
307
|
var emitted: int = passed.size()
|
|
300
308
|
var unbound: int = callable.get_unbound_arguments_count()
|
|
301
309
|
passed = passed.slice(0, maxi(emitted - unbound, 0))
|
|
@@ -305,7 +313,7 @@ static func _misfit(source: Node, signal_name: String, callable: Callable, flags
|
|
|
305
313
|
if bound is Object:
|
|
306
314
|
var object: Object = bound
|
|
307
315
|
bound_class = object.get_class()
|
|
308
|
-
passed.append({"name": "bound", "type": typeof(bound), "class_name": bound_class})
|
|
316
|
+
passed.append({ "name": "bound", "type": typeof(bound), "class_name": bound_class })
|
|
309
317
|
var binds: int = passed.size() - from_signal
|
|
310
318
|
|
|
311
319
|
# What the method is called with, said in the parts that make it: an answer counting the bound
|
|
@@ -331,9 +339,10 @@ static func _misfit(source: Node, signal_name: String, callable: Callable, flags
|
|
|
331
339
|
return "%s needs %d%s" % [called, needed, FAILS]
|
|
332
340
|
if passed.size() > parameters.size():
|
|
333
341
|
var most: String = "none" if parameters.is_empty() else "at most %d" % parameters.size()
|
|
334
|
-
# Said with the misfit, since unbinds is what a connection to a method wanting less is for,
|
|
335
|
-
# only when the extra arguments are the signal's: a scene's connection unbinds the
|
|
336
|
-
# the signal passes before it adds the bound ones, so a bound one is never
|
|
342
|
+
# Said with the misfit, since unbinds is what a connection to a method wanting less is for,
|
|
343
|
+
# and only when the extra arguments are the signal's: a scene's connection unbinds the
|
|
344
|
+
# arguments the signal passes before it adds the bound ones, so a bound one is never
|
|
345
|
+
# dropped.
|
|
337
346
|
var extra: int = passed.size() - parameters.size()
|
|
338
347
|
var remedy: String = (
|
|
339
348
|
(
|
|
@@ -362,7 +371,7 @@ static func _misfit(source: Node, signal_name: String, callable: Callable, flags
|
|
|
362
371
|
method,
|
|
363
372
|
str(parameter.get("name", "")),
|
|
364
373
|
_type_named(parameter),
|
|
365
|
-
FAILS
|
|
374
|
+
FAILS,
|
|
366
375
|
]
|
|
367
376
|
)
|
|
368
377
|
return ""
|
|
@@ -437,7 +446,7 @@ func disconnect_signal(args: Dictionary) -> Dictionary:
|
|
|
437
446
|
or target_node_path.is_empty()
|
|
438
447
|
or method_name.is_empty()
|
|
439
448
|
):
|
|
440
|
-
return {"ok": false, "error": "Missing required signal disconnection arguments"}
|
|
449
|
+
return { "ok": false, "error": "Missing required signal disconnection arguments" }
|
|
441
450
|
|
|
442
451
|
var scene: GdhSceneFile = GdhSceneFile.new()
|
|
443
452
|
var refused: Dictionary = scene.open(scene_path, true)
|
|
@@ -473,11 +482,14 @@ func disconnect_signal(args: Dictionary) -> Dictionary:
|
|
|
473
482
|
"The connection from %s.%s to %s.%s is made by %s"
|
|
474
483
|
% [named_from, signal_name, named_to, method_name, made_in]
|
|
475
484
|
)
|
|
476
|
-
return
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
485
|
+
return (
|
|
486
|
+
scene
|
|
487
|
+
. refuse(
|
|
488
|
+
(
|
|
489
|
+
made_by
|
|
490
|
+
+ ", and this scene saves nothing about it: disconnect it there, which changes "
|
|
491
|
+
+ "every scene using it."
|
|
492
|
+
)
|
|
481
493
|
)
|
|
482
494
|
)
|
|
483
495
|
var callable: Callable = held["callable"]
|
|
@@ -550,8 +562,8 @@ func list_connections(args: Dictionary) -> Dictionary:
|
|
|
550
562
|
if target_obj is Node:
|
|
551
563
|
target_path = str(root.get_path_to(target_obj as Node))
|
|
552
564
|
editable = editable and scene.foreign(target_obj as Node).is_empty()
|
|
553
|
-
# A connection an instanced scene makes on its own root sits on a node this scene
|
|
554
|
-
# so the ends alone read it as one this scene could change.
|
|
565
|
+
# A connection an instanced scene makes on its own root sits on a node this scene
|
|
566
|
+
# owns, so the ends alone read it as one this scene could change.
|
|
555
567
|
var made_in: String = _made_in(scene, node, flags)
|
|
556
568
|
var listed: Dictionary = {
|
|
557
569
|
"sourceNodePath": path,
|
|
@@ -561,7 +573,8 @@ func list_connections(args: Dictionary) -> Dictionary:
|
|
|
561
573
|
"flags": flags,
|
|
562
574
|
"flagNames": flag_names(flags),
|
|
563
575
|
"editable": editable and made_in.is_empty(),
|
|
564
|
-
"methodFound":
|
|
576
|
+
"methodFound":
|
|
577
|
+
target_obj != null and target_obj.has_method(callable.get_method()),
|
|
565
578
|
}
|
|
566
579
|
if not made_in.is_empty():
|
|
567
580
|
listed["madeIn"] = made_in
|
|
@@ -576,14 +589,14 @@ func list_connections(args: Dictionary) -> Dictionary:
|
|
|
576
589
|
connections.append(listed)
|
|
577
590
|
|
|
578
591
|
scene.close()
|
|
579
|
-
var answer: Dictionary = {"ok": true, "connections": connections}
|
|
592
|
+
var answer: Dictionary = { "ok": true, "connections": connections }
|
|
580
593
|
if Engine.is_editor_hint():
|
|
581
594
|
answer["unsavedInEditor"] = GdhSceneFile.unsaved(scene_path)
|
|
582
595
|
return answer
|
|
583
596
|
|
|
584
597
|
|
|
585
598
|
func _collect_nodes_recursive(node: Node, path: String, out_nodes: Array) -> void:
|
|
586
|
-
out_nodes.append({"path": path, "node": node})
|
|
599
|
+
out_nodes.append({ "path": path, "node": node })
|
|
587
600
|
for child: Node in node.get_children():
|
|
588
601
|
var child_path: String = str(child.name) if path == "." else path + "/" + str(child.name)
|
|
589
602
|
_collect_nodes_recursive(child, child_path, out_nodes)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
@tool
|
|
2
2
|
extends "resource_tools.gd"
|
|
3
|
-
|
|
4
3
|
## TileSets and the cells of tile maps, beside the resource files the script it extends writes,
|
|
5
4
|
## whose helpers it shares.
|
|
6
5
|
|
|
@@ -30,7 +29,10 @@ func _xy(value: Variant, label: String) -> Array:
|
|
|
30
29
|
):
|
|
31
30
|
return [
|
|
32
31
|
false,
|
|
33
|
-
|
|
32
|
+
(
|
|
33
|
+
'%s must be two whole numbers, {"x": .., "y": ..}, not %s.'
|
|
34
|
+
% [label, JSON.stringify(value)]
|
|
35
|
+
),
|
|
34
36
|
]
|
|
35
37
|
return [true, Vector2i(GdhRead.as_int(x), GdhRead.as_int(y))]
|
|
36
38
|
|
|
@@ -38,36 +40,36 @@ func _xy(value: Variant, label: String) -> Array:
|
|
|
38
40
|
func create_tileset(args: Dictionary) -> Dictionary:
|
|
39
41
|
var tileset_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
40
42
|
if tileset_path == "res://":
|
|
41
|
-
return {"ok": false, "error": "resourcePath is required"}
|
|
43
|
+
return { "ok": false, "error": "resourcePath is required" }
|
|
42
44
|
# modify sets properties and builds no atlas, so the other path is the only way on offered.
|
|
43
45
|
var taken: String = (
|
|
44
46
|
""
|
|
45
47
|
if not FileAccess.file_exists(tileset_path)
|
|
46
48
|
else (
|
|
47
49
|
(
|
|
48
|
-
"%s already exists, and create_tileset builds a whole new TileSet, which would
|
|
49
|
-
+ "everything in it, the tiles a scene paints with among them. Give
|
|
50
|
-
+ "nothing is at."
|
|
50
|
+
"%s already exists, and create_tileset builds a whole new TileSet, which would "
|
|
51
|
+
+ "replace everything in it, the tiles a scene paints with among them. Give "
|
|
52
|
+
+ "resourcePath a path nothing is at."
|
|
51
53
|
)
|
|
52
54
|
% tileset_path
|
|
53
55
|
)
|
|
54
56
|
)
|
|
55
57
|
if not taken.is_empty():
|
|
56
|
-
return {"ok": false, "error": taken}
|
|
58
|
+
return { "ok": false, "error": taken }
|
|
57
59
|
|
|
58
60
|
var given: Variant = args.get("sources", [])
|
|
59
61
|
if not given is Array:
|
|
60
|
-
return {"ok": false, "error": "sources must list at least one atlas"}
|
|
62
|
+
return { "ok": false, "error": "sources must list at least one atlas" }
|
|
61
63
|
var sources: Array = given
|
|
62
64
|
if sources.is_empty():
|
|
63
|
-
return {"ok": false, "error": "sources must list at least one atlas"}
|
|
65
|
+
return { "ok": false, "error": "sources must list at least one atlas" }
|
|
64
66
|
|
|
65
67
|
var tileset: TileSet = TileSet.new()
|
|
66
68
|
var made: Array = []
|
|
67
69
|
for index: int in sources.size():
|
|
68
70
|
var built: Array = _atlas(sources[index], index)
|
|
69
71
|
if not built[0]:
|
|
70
|
-
return {"ok": false, "error": built[1]}
|
|
72
|
+
return { "ok": false, "error": built[1] }
|
|
71
73
|
var atlas: TileSetAtlasSource = built[1]
|
|
72
74
|
# The first source sets the tile set's own tile size, which is what a TileMapLayer draws
|
|
73
75
|
# cells at; left at its default of 16 it did not match the atlas.
|
|
@@ -77,10 +79,12 @@ func create_tileset(args: Dictionary) -> Dictionary:
|
|
|
77
79
|
if added < 0:
|
|
78
80
|
return {
|
|
79
81
|
"ok": false,
|
|
80
|
-
"error": "The TileSet did not take the atlas for %s" % atlas.texture.resource_path
|
|
82
|
+
"error": "The TileSet did not take the atlas for %s" % atlas.texture.resource_path,
|
|
81
83
|
}
|
|
82
84
|
var entry: Dictionary = {
|
|
83
|
-
"sourceId": added,
|
|
85
|
+
"sourceId": added,
|
|
86
|
+
"texture": atlas.texture.resource_path,
|
|
87
|
+
"tiles": atlas.get_tiles_count(),
|
|
84
88
|
}
|
|
85
89
|
var blank: Array = built[2]
|
|
86
90
|
if not blank.is_empty():
|
|
@@ -92,18 +96,20 @@ func create_tileset(args: Dictionary) -> Dictionary:
|
|
|
92
96
|
|
|
93
97
|
var folder: String = GdhSceneFile.make_folder_for(tileset_path)
|
|
94
98
|
if not folder.is_empty():
|
|
95
|
-
return {"ok": false, "error": folder}
|
|
99
|
+
return { "ok": false, "error": folder }
|
|
96
100
|
var saving: Error = GdhSceneUids.save_keeping_uid(tileset, tileset_path)
|
|
97
101
|
if saving != OK:
|
|
98
|
-
return {
|
|
102
|
+
return {
|
|
103
|
+
"ok": false, "error": "Failed to save %s: %s" % [tileset_path, error_string(saving)],
|
|
104
|
+
}
|
|
99
105
|
|
|
100
106
|
_written(tileset_path)
|
|
101
107
|
# The size cells are drawn at, which the file leaves out when it is the default 16 by 16.
|
|
102
108
|
return {
|
|
103
109
|
"ok": true,
|
|
104
110
|
"tilesetPath": tileset_path,
|
|
105
|
-
"tileSize": {"x": tileset.tile_size.x, "y": tileset.tile_size.y},
|
|
106
|
-
"sources": made
|
|
111
|
+
"tileSize": { "x": tileset.tile_size.x, "y": tileset.tile_size.y },
|
|
112
|
+
"sources": made,
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
|
|
@@ -127,18 +133,22 @@ func _atlas(entry: Variant, index: int) -> Array:
|
|
|
127
133
|
if texture_path.split("/").has(".."):
|
|
128
134
|
return [false, "sources[%d].texture leaves the project: %s" % [index, texture_path]]
|
|
129
135
|
if not ResourceLoader.exists(texture_path):
|
|
130
|
-
# An image the engine has not imported loads as nothing, where "no texture" would send a
|
|
131
|
-
# looking for a file that is there.
|
|
132
|
-
if
|
|
136
|
+
# An image the engine has not imported loads as nothing, where "no texture" would send a
|
|
137
|
+
# caller looking for a file that is there.
|
|
138
|
+
if (
|
|
139
|
+
FileAccess.file_exists(texture_path)
|
|
140
|
+
and not FileAccess.file_exists(texture_path + ".import")
|
|
141
|
+
):
|
|
133
142
|
return [
|
|
134
143
|
false,
|
|
135
144
|
(
|
|
136
145
|
(
|
|
137
|
-
"sources[%d].texture: %s has not been imported, so the engine has no
|
|
138
|
-
+ "yet. project_import reimport with resourcePath %s
|
|
146
|
+
"sources[%d].texture: %s has not been imported, so the engine has no "
|
|
147
|
+
+ "texture for it yet. project_import reimport with resourcePath %s "
|
|
148
|
+
+ "imports it."
|
|
139
149
|
)
|
|
140
150
|
% [index, texture_path, texture_path]
|
|
141
|
-
)
|
|
151
|
+
),
|
|
142
152
|
]
|
|
143
153
|
return [false, "sources[%d].texture: no texture at %s" % [index, texture_path]]
|
|
144
154
|
var texture: Texture2D = load(texture_path) as Texture2D
|
|
@@ -173,7 +183,7 @@ func _atlas(entry: Variant, index: int) -> Array:
|
|
|
173
183
|
(
|
|
174
184
|
"sources[%d]: a %s tile does not fit in %s, which is %s"
|
|
175
185
|
% [index, tile_size, texture_path, texture.get_size()]
|
|
176
|
-
)
|
|
186
|
+
),
|
|
177
187
|
]
|
|
178
188
|
var image: Image = texture.get_image()
|
|
179
189
|
var blank: Array = []
|
|
@@ -186,10 +196,12 @@ func _atlas(entry: Variant, index: int) -> Array:
|
|
|
186
196
|
atlas.texture_region_size
|
|
187
197
|
)
|
|
188
198
|
if image != null and _blank(image, region):
|
|
189
|
-
blank.append({"x": x, "y": y})
|
|
199
|
+
blank.append({ "x": x, "y": y })
|
|
190
200
|
continue
|
|
191
201
|
atlas.create_tile(cell)
|
|
192
|
-
var covered: Vector2i =
|
|
202
|
+
var covered: Vector2i = (
|
|
203
|
+
atlas.margins + grid * tile_size + (grid - Vector2i.ONE) * atlas.separation
|
|
204
|
+
)
|
|
193
205
|
var left: Vector2i = Vector2i(texture.get_size()) - covered
|
|
194
206
|
var sides: PackedStringArray = []
|
|
195
207
|
if left.x > 0:
|
|
@@ -208,7 +220,7 @@ func _atlas(entry: Variant, index: int) -> Array:
|
|
|
208
220
|
" and ".join(sides),
|
|
209
221
|
"is" if sides.size() == 1 else "are",
|
|
210
222
|
tile_size.x,
|
|
211
|
-
tile_size.y
|
|
223
|
+
tile_size.y,
|
|
212
224
|
]
|
|
213
225
|
)
|
|
214
226
|
)
|
|
@@ -236,16 +248,16 @@ func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
|
236
248
|
var scene_path: String = _ensure_res_path(str(args.get("scenePath", "")))
|
|
237
249
|
var node_path: String = str(args.get("nodePath", ""))
|
|
238
250
|
if scene_path == "res://":
|
|
239
|
-
return {"ok": false, "error": "scenePath is required"}
|
|
251
|
+
return { "ok": false, "error": "scenePath is required" }
|
|
240
252
|
|
|
241
253
|
var cells: Variant = args.get("cells", [])
|
|
242
254
|
# Refused rather than skipped: placing nothing and answering success is indistinguishable
|
|
243
255
|
# from placing everything, and the caller only finds out by opening the scene.
|
|
244
256
|
if typeof(cells) != TYPE_ARRAY:
|
|
245
|
-
return {"ok": false, "error": "cells must be an array of cells to place"}
|
|
257
|
+
return { "ok": false, "error": "cells must be an array of cells to place" }
|
|
246
258
|
var placed: Array = cells
|
|
247
259
|
if placed.is_empty():
|
|
248
|
-
return {"ok": false, "error": "cells is empty, so there is nothing to place"}
|
|
260
|
+
return { "ok": false, "error": "cells is empty, so there is nothing to place" }
|
|
249
261
|
|
|
250
262
|
var scene: GdhSceneFile = GdhSceneFile.new()
|
|
251
263
|
var refused: Dictionary = scene.open(scene_path, true)
|
|
@@ -260,14 +272,14 @@ func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
|
260
272
|
var layered: TileMap = node as TileMap
|
|
261
273
|
var single: TileMapLayer = node as TileMapLayer
|
|
262
274
|
|
|
263
|
-
# set_cell stores a cell whatever it is given, and a cell naming no tile simply draws nothing,
|
|
264
|
-
# the source, the tile and its alternative are checked here: the alternative is a call that
|
|
275
|
+
# set_cell stores a cell whatever it is given, and a cell naming no tile simply draws nothing,
|
|
276
|
+
# so the source, the tile and its alternative are checked here: the alternative is a call that
|
|
265
277
|
# reports placing tiles and a scene that shows none.
|
|
266
278
|
var tile_set: TileSet = layered.tile_set if layered != null else single.tile_set
|
|
267
279
|
|
|
268
280
|
scene.asked(node, ["layer_%d/tile_data" % layer if layered != null else "tile_map_data"])
|
|
269
|
-
# Every cell is checked before any is placed, and every one refused is named: stopping at the
|
|
270
|
-
# left a caller fixing one cell a call.
|
|
281
|
+
# Every cell is checked before any is placed, and every one refused is named: stopping at the
|
|
282
|
+
# first left a caller fixing one cell a call.
|
|
271
283
|
var checked: Array = []
|
|
272
284
|
var refusals: PackedStringArray = []
|
|
273
285
|
for index: int in placed.size():
|
|
@@ -311,7 +323,7 @@ func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
|
311
323
|
"layer": layer,
|
|
312
324
|
"placed": wanted.size() - erased,
|
|
313
325
|
"erased": erased,
|
|
314
|
-
"requested": placed.size()
|
|
326
|
+
"requested": placed.size(),
|
|
315
327
|
}
|
|
316
328
|
|
|
317
329
|
|
|
@@ -319,7 +331,9 @@ func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
|
319
331
|
## TileMapLayer is the node since 4.3, and TileMap the one it replaced, which keeps its layers.
|
|
320
332
|
func _tile_node(scene: GdhSceneFile, node_path: String, layer: int) -> Array:
|
|
321
333
|
var node: Node = (
|
|
322
|
-
scene.root
|
|
334
|
+
scene.root
|
|
335
|
+
if node_path == "." or node_path == ""
|
|
336
|
+
else scene.root.get_node_or_null(node_path)
|
|
323
337
|
)
|
|
324
338
|
if node == null:
|
|
325
339
|
return [null, "No node at %s in %s" % [node_path, scene.path]]
|
|
@@ -331,20 +345,27 @@ func _tile_node(scene: GdhSceneFile, node_path: String, layer: int) -> Array:
|
|
|
331
345
|
if not foreign.is_empty():
|
|
332
346
|
return [null, foreign]
|
|
333
347
|
if single != null and layer != 0:
|
|
334
|
-
return [
|
|
348
|
+
return [
|
|
349
|
+
null,
|
|
350
|
+
"%s is a TileMapLayer, which is one layer; layer applies to a TileMap" % node_path,
|
|
351
|
+
]
|
|
335
352
|
if layered != null and (layer < 0 or layer >= layered.get_layers_count()):
|
|
336
|
-
return [
|
|
353
|
+
return [
|
|
354
|
+
null,
|
|
355
|
+
"%s has %d layers, and no layer %d" % [node_path, layered.get_layers_count(), layer],
|
|
356
|
+
]
|
|
337
357
|
var tile_set: TileSet = layered.tile_set if layered != null else single.tile_set
|
|
338
358
|
if tile_set == null:
|
|
339
359
|
return [
|
|
340
360
|
null,
|
|
341
361
|
(
|
|
342
362
|
(
|
|
343
|
-
|
|
344
|
-
+ '"res://..."} on %s gives it one, a TileSet file
|
|
363
|
+
"%s has no TileSet, so no cell can name a source. scene_node set with "
|
|
364
|
+
+ 'properties {"tile_set": "res://..."} on %s gives it one, a TileSet file '
|
|
365
|
+
+ "such as resource_edit create_tileset makes."
|
|
345
366
|
)
|
|
346
367
|
% [node_path, node_path]
|
|
347
|
-
)
|
|
368
|
+
),
|
|
348
369
|
]
|
|
349
370
|
return [node, ""]
|
|
350
371
|
|
|
@@ -369,7 +390,8 @@ func _cell(entry: Variant, index: int, tile_set: TileSet) -> Array:
|
|
|
369
390
|
return [true, coords, -1, Vector2i(-1, -1), -1]
|
|
370
391
|
if not cell.has("atlasCoords"):
|
|
371
392
|
return [
|
|
372
|
-
false,
|
|
393
|
+
false,
|
|
394
|
+
"%s has no atlasCoords, which every cell but an erased one (sourceId -1) needs" % named,
|
|
373
395
|
]
|
|
374
396
|
var atlas_at: Array = _xy(cell["atlasCoords"], "cells[%d].atlasCoords" % index)
|
|
375
397
|
if not atlas_at[0]:
|
|
@@ -380,7 +402,7 @@ func _cell(entry: Variant, index: int, tile_set: TileSet) -> Array:
|
|
|
380
402
|
(
|
|
381
403
|
"%s names source %d, and the TileSet has %s; sourceId -1 erases a cell"
|
|
382
404
|
% [named, source_id, _sources_of(tile_set)]
|
|
383
|
-
)
|
|
405
|
+
),
|
|
384
406
|
]
|
|
385
407
|
var source: TileSetSource = tile_set.get_source(source_id)
|
|
386
408
|
var atlas_coords: Vector2i = atlas_at[1]
|
|
@@ -388,7 +410,10 @@ func _cell(entry: Variant, index: int, tile_set: TileSet) -> Array:
|
|
|
388
410
|
if not source.has_tile(atlas_coords):
|
|
389
411
|
return [
|
|
390
412
|
false,
|
|
391
|
-
|
|
413
|
+
(
|
|
414
|
+
"%s: source %d has no tile at %s; it has %s"
|
|
415
|
+
% [named, source_id, atlas_coords, _tiles_of(source)]
|
|
416
|
+
),
|
|
392
417
|
]
|
|
393
418
|
if not source.has_alternative_tile(atlas_coords, alternative):
|
|
394
419
|
return [
|
|
@@ -396,7 +421,7 @@ func _cell(entry: Variant, index: int, tile_set: TileSet) -> Array:
|
|
|
396
421
|
(
|
|
397
422
|
"%s: the tile at %s in source %d has no alternative %d"
|
|
398
423
|
% [named, atlas_coords, source_id, alternative]
|
|
399
|
-
)
|
|
424
|
+
),
|
|
400
425
|
]
|
|
401
426
|
return [true, coords, source_id, atlas_coords, alternative]
|
|
402
427
|
|
|
@@ -452,17 +477,19 @@ static func cells_of(node: Node) -> Dictionary:
|
|
|
452
477
|
listed.append(entry)
|
|
453
478
|
else:
|
|
454
479
|
return {}
|
|
455
|
-
var answer: Dictionary = {"cellCount": count, "cells": listed}
|
|
480
|
+
var answer: Dictionary = { "cellCount": count, "cells": listed }
|
|
456
481
|
if count > listed.size():
|
|
457
482
|
answer["cellsNote"] = "The first %d of %d cells are listed." % [listed.size(), count]
|
|
458
483
|
return answer
|
|
459
484
|
|
|
460
485
|
|
|
461
|
-
static func _cell_entry(
|
|
486
|
+
static func _cell_entry(
|
|
487
|
+
at: Vector2i, source_id: int, atlas: Vector2i, alternative: int
|
|
488
|
+
) -> Dictionary:
|
|
462
489
|
return {
|
|
463
|
-
"coords": {"x": at.x, "y": at.y},
|
|
490
|
+
"coords": { "x": at.x, "y": at.y },
|
|
464
491
|
"sourceId": source_id,
|
|
465
|
-
"atlasCoords": {"x": atlas.x, "y": atlas.y},
|
|
492
|
+
"atlasCoords": { "x": atlas.x, "y": atlas.y },
|
|
466
493
|
"alternativeTile": alternative,
|
|
467
494
|
}
|
|
468
495
|
|
|
@@ -473,13 +500,13 @@ func _cell_at(node: Node, layer: int, at: Vector2i) -> Array:
|
|
|
473
500
|
return [
|
|
474
501
|
layered.get_cell_source_id(layer, at),
|
|
475
502
|
layered.get_cell_atlas_coords(layer, at),
|
|
476
|
-
layered.get_cell_alternative_tile(layer, at)
|
|
503
|
+
layered.get_cell_alternative_tile(layer, at),
|
|
477
504
|
]
|
|
478
505
|
var single: TileMapLayer = node as TileMapLayer
|
|
479
506
|
if single != null:
|
|
480
507
|
return [
|
|
481
508
|
single.get_cell_source_id(at),
|
|
482
509
|
single.get_cell_atlas_coords(at),
|
|
483
|
-
single.get_cell_alternative_tile(at)
|
|
510
|
+
single.get_cell_alternative_tile(at),
|
|
484
511
|
]
|
|
485
512
|
return []
|
|
@@ -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)
|
|
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"
|
|
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,5 +1,4 @@
|
|
|
1
1
|
extends Logger
|
|
2
|
-
|
|
3
2
|
## What the engine reports on the main thread while one call runs, added for that call alone.
|
|
4
3
|
##
|
|
5
4
|
## A call the engine refuses, given too few arguments or one it will not convert, comes back from
|
|
@@ -27,7 +26,7 @@ func _log_message(_message: String, _error: bool) -> void:
|
|
|
27
26
|
|
|
28
27
|
|
|
29
28
|
# The engine's own signature for a Logger, eight parameters and not this project's to shape.
|
|
30
|
-
#
|
|
29
|
+
# gdstyle:ignore=quality/max-parameters
|
|
31
30
|
func _log_error(
|
|
32
31
|
function: String,
|
|
33
32
|
file: String,
|