gdharness 1.3.8 → 1.3.10
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 +4668 -3229
- package/build/godot/addons/gdharness_editor/animation_reads.gd +115 -4
- package/build/godot/addons/gdharness_editor/declared_values.gd +272 -0
- package/build/godot/addons/gdharness_editor/file_reads.gd +115 -18
- package/build/godot/addons/gdharness_editor/headless_check.gd +49 -2
- package/build/godot/addons/gdharness_editor/property_paths.gd +89 -16
- package/build/godot/addons/gdharness_editor/property_values.gd +180 -121
- package/build/godot/addons/gdharness_editor/reading.gd +112 -6
- package/build/godot/addons/gdharness_editor/scene_file.gd +117 -174
- package/build/godot/addons/gdharness_editor/scene_uids.gd +107 -0
- package/build/godot/addons/gdharness_editor/scene_uids.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/serialisation.gd +19 -29
- package/build/godot/addons/gdharness_editor/setting_reads.gd +121 -0
- package/build/godot/addons/gdharness_editor/setting_reads.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tool_executor.gd +39 -6
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd +263 -0
- package/build/godot/addons/gdharness_editor/tools/animation_states.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/animation_tools.gd +49 -414
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd +464 -0
- package/build/godot/addons/gdharness_editor/tools/animation_tracks.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/class_tools.gd +37 -0
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd +221 -0
- package/build/godot/addons/gdharness_editor/tools/navigation_bake.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +162 -483
- package/build/godot/addons/gdharness_editor/tools/scene_groups.gd +16 -0
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +8 -4
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +2 -1
- package/build/godot/addons/gdharness_editor/tools/scene_placing.gd +10 -0
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +151 -8
- package/build/godot/addons/gdharness_editor/tools/settings_tools.gd +7 -30
- package/build/godot/addons/gdharness_editor/tools/signal_tools.gd +190 -38
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd +485 -0
- package/build/godot/addons/gdharness_editor/tools/tileset_tools.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/value_shapes.gd +128 -1
- package/build/godot/addons/gdharness_runtime/call_errors.gd +8 -2
- package/build/godot/addons/gdharness_runtime/declared_values.gd +272 -0
- package/build/godot/addons/gdharness_runtime/reading.gd +112 -6
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +35 -3
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +5 -0
- package/build/godot/addons/gdharness_runtime/runtime_changes.gd +188 -30
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +107 -104
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +17 -0
- package/build/godot/addons/gdharness_runtime/runtime_pad.gd +13 -4
- package/build/godot/addons/gdharness_runtime/runtime_paths.gd +320 -27
- package/build/godot/addons/gdharness_runtime/runtime_queries.gd +165 -20
- package/build/godot/addons/gdharness_runtime/runtime_screen.gd +49 -3
- package/build/godot/addons/gdharness_runtime/runtime_targets.gd +31 -2
- package/build/godot/addons/gdharness_runtime/runtime_values.gd +250 -10
- package/build/godot/addons/gdharness_runtime/runtime_waits.gd +279 -11
- package/build/godot/addons/gdharness_runtime/runtime_words.gd +27 -0
- package/build/godot/addons/gdharness_runtime/serialisation.gd +19 -29
- package/build/godot/addons/gdharness_runtime/value_shapes.gd +128 -1
- package/build/godot/operations/animation_reads.gd +115 -4
- package/build/godot/operations/audio_buses.gd +93 -7
- package/build/godot/operations/classdb_queries.gd +119 -7
- package/build/godot/operations/declared_values.gd +272 -0
- package/build/godot/operations/dependencies.gd +154 -41
- package/build/godot/operations/editor_tools.gd +29 -13
- package/build/godot/operations/export_presets.gd +602 -4
- package/build/godot/operations/file_reads.gd +115 -18
- package/build/godot/operations/gdscript_analysis.gd +14 -0
- package/build/godot/operations/gdscript_authoring.gd +12 -2
- package/build/godot/operations/godot_operations.gd +18 -2
- package/build/godot/operations/import_pipeline.gd +20 -221
- package/build/godot/operations/input_actions.gd +127 -51
- package/build/godot/operations/project_config.gd +113 -68
- package/build/godot/operations/project_diagnostics.gd +4 -0
- package/build/godot/operations/project_validation.gd +266 -0
- package/build/godot/operations/property_paths.gd +89 -16
- package/build/godot/operations/property_values.gd +180 -121
- package/build/godot/operations/reading.gd +112 -6
- package/build/godot/operations/scene_connections.gd +222 -0
- package/build/godot/operations/serialisation.gd +19 -29
- package/build/godot/operations/setting_reads.gd +121 -0
- package/build/godot/operations/value_shapes.gd +128 -1
- package/build/godot/tests/listed.gd +20 -13
- package/build/keeper.js +1402 -707
- package/package.json +1 -1
|
@@ -52,7 +52,108 @@ const MAP_CALLS: Array[String] = [
|
|
|
52
52
|
]
|
|
53
53
|
## The calls a path makes on a packed list, which has fewer than a list: measured on 4.7.2, it has no
|
|
54
54
|
## front(), back(), max(), min() or hash().
|
|
55
|
-
const PACKED_CALLS: Array[String] = ["size", "is_empty", "duplicate"
|
|
55
|
+
const PACKED_CALLS: Array[String] = ["size", "is_empty", "duplicate"]
|
|
56
|
+
## What a packed list of bytes answers beside those, read as another list or as text. It has no
|
|
57
|
+
## to_byte_array(), which every other packed list has.
|
|
58
|
+
const BYTE_CALLS: Array[String] = [
|
|
59
|
+
"to_int32_array",
|
|
60
|
+
"to_int64_array",
|
|
61
|
+
"to_float32_array",
|
|
62
|
+
"to_float64_array",
|
|
63
|
+
"get_string_from_utf8",
|
|
64
|
+
"get_string_from_utf32",
|
|
65
|
+
"hex_encode",
|
|
66
|
+
]
|
|
67
|
+
## The methods a list, a map and a packed list have that change what they are called on, as the
|
|
68
|
+
## engine's API marks them, and those that read it given arguments. A path makes neither, and a call
|
|
69
|
+
## refused for one is pointed at a write or a whole read instead of at an element, since a method of
|
|
70
|
+
## the list itself was the aim.
|
|
71
|
+
const LIST_CHANGES: Array[String] = [
|
|
72
|
+
"clear",
|
|
73
|
+
"assign",
|
|
74
|
+
"set",
|
|
75
|
+
"push_back",
|
|
76
|
+
"push_front",
|
|
77
|
+
"append",
|
|
78
|
+
"append_array",
|
|
79
|
+
"resize",
|
|
80
|
+
"insert",
|
|
81
|
+
"remove_at",
|
|
82
|
+
"fill",
|
|
83
|
+
"erase",
|
|
84
|
+
"pop_back",
|
|
85
|
+
"pop_front",
|
|
86
|
+
"pop_at",
|
|
87
|
+
"sort",
|
|
88
|
+
"sort_custom",
|
|
89
|
+
"shuffle",
|
|
90
|
+
"reverse",
|
|
91
|
+
"make_read_only",
|
|
92
|
+
]
|
|
93
|
+
const LIST_READS: Array[String] = [
|
|
94
|
+
"get",
|
|
95
|
+
"find",
|
|
96
|
+
"find_custom",
|
|
97
|
+
"rfind",
|
|
98
|
+
"rfind_custom",
|
|
99
|
+
"count",
|
|
100
|
+
"has",
|
|
101
|
+
"bsearch",
|
|
102
|
+
"bsearch_custom",
|
|
103
|
+
"slice",
|
|
104
|
+
"filter",
|
|
105
|
+
"map",
|
|
106
|
+
"reduce",
|
|
107
|
+
"any",
|
|
108
|
+
"all",
|
|
109
|
+
"is_same_typed",
|
|
110
|
+
]
|
|
111
|
+
const MAP_CHANGES: Array[String] = [
|
|
112
|
+
"clear", "assign", "sort", "merge", "erase", "get_or_add", "set", "make_read_only"
|
|
113
|
+
]
|
|
114
|
+
const MAP_READS: Array[String] = [
|
|
115
|
+
"merged",
|
|
116
|
+
"has",
|
|
117
|
+
"has_all",
|
|
118
|
+
"find_key",
|
|
119
|
+
"get",
|
|
120
|
+
"is_same_typed",
|
|
121
|
+
"is_same_typed_key",
|
|
122
|
+
"is_same_typed_value",
|
|
123
|
+
"recursive_equal",
|
|
124
|
+
]
|
|
125
|
+
const PACKED_CHANGES: Array[String] = [
|
|
126
|
+
"set",
|
|
127
|
+
"push_back",
|
|
128
|
+
"append",
|
|
129
|
+
"append_array",
|
|
130
|
+
"remove_at",
|
|
131
|
+
"insert",
|
|
132
|
+
"fill",
|
|
133
|
+
"resize",
|
|
134
|
+
"clear",
|
|
135
|
+
"reverse",
|
|
136
|
+
"sort",
|
|
137
|
+
"erase",
|
|
138
|
+
]
|
|
139
|
+
const PACKED_READS: Array[String] = ["get", "has", "slice", "bsearch", "find", "rfind", "count"]
|
|
140
|
+
## The calls a path makes on a string. A word that looks right and does not match is told apart by
|
|
141
|
+
## its code points, "label:text:to_utf32_buffer():to_int32_array()", which show a non-breaking space
|
|
142
|
+
## as 160 where the answer's JSON shows a space.
|
|
143
|
+
const STRING_CALLS: Array[String] = [
|
|
144
|
+
"length",
|
|
145
|
+
"is_empty",
|
|
146
|
+
"strip_edges",
|
|
147
|
+
"to_lower",
|
|
148
|
+
"to_upper",
|
|
149
|
+
"c_escape",
|
|
150
|
+
"json_escape",
|
|
151
|
+
"is_valid_int",
|
|
152
|
+
"to_int",
|
|
153
|
+
"to_float",
|
|
154
|
+
"to_utf8_buffer",
|
|
155
|
+
"to_utf32_buffer",
|
|
156
|
+
]
|
|
56
157
|
## The packed lists, which a game keeps names and points in as often as it keeps them in an Array.
|
|
57
158
|
const PACKED: Array[int] = [
|
|
58
159
|
TYPE_PACKED_BYTE_ARRAY,
|
|
@@ -66,6 +167,108 @@ const PACKED: Array[int] = [
|
|
|
66
167
|
TYPE_PACKED_COLOR_ARRAY,
|
|
67
168
|
TYPE_PACKED_VECTOR4_ARRAY,
|
|
68
169
|
]
|
|
170
|
+
## The calls a path makes on a vector, a colour, a rectangle or a transform, by its type: those that
|
|
171
|
+
## take no arguments, as the engine has them on 4.7.2. Named for the reason the list calls are, and
|
|
172
|
+
## none can change what it is called on, since such a value is a copy wherever it is read from. A
|
|
173
|
+
## wait for something to come to rest reads "linear_velocity:length()".
|
|
174
|
+
const VALUE_CALLS: Dictionary = {
|
|
175
|
+
TYPE_VECTOR2:
|
|
176
|
+
[
|
|
177
|
+
"length",
|
|
178
|
+
"length_squared",
|
|
179
|
+
"normalized",
|
|
180
|
+
"abs",
|
|
181
|
+
"sign",
|
|
182
|
+
"floor",
|
|
183
|
+
"ceil",
|
|
184
|
+
"round",
|
|
185
|
+
"angle",
|
|
186
|
+
"aspect",
|
|
187
|
+
"is_normalized",
|
|
188
|
+
"is_zero_approx",
|
|
189
|
+
"is_finite",
|
|
190
|
+
"orthogonal",
|
|
191
|
+
"max_axis_index",
|
|
192
|
+
"min_axis_index",
|
|
193
|
+
],
|
|
194
|
+
TYPE_VECTOR2I: ["length", "length_squared", "abs", "sign", "aspect", "max_axis_index", "min_axis_index"],
|
|
195
|
+
TYPE_VECTOR3:
|
|
196
|
+
[
|
|
197
|
+
"length",
|
|
198
|
+
"length_squared",
|
|
199
|
+
"normalized",
|
|
200
|
+
"abs",
|
|
201
|
+
"sign",
|
|
202
|
+
"floor",
|
|
203
|
+
"ceil",
|
|
204
|
+
"round",
|
|
205
|
+
"is_normalized",
|
|
206
|
+
"is_zero_approx",
|
|
207
|
+
"is_finite",
|
|
208
|
+
"max_axis_index",
|
|
209
|
+
"min_axis_index",
|
|
210
|
+
"inverse",
|
|
211
|
+
],
|
|
212
|
+
TYPE_VECTOR3I: ["length", "length_squared", "abs", "sign", "max_axis_index", "min_axis_index"],
|
|
213
|
+
TYPE_VECTOR4:
|
|
214
|
+
[
|
|
215
|
+
"length",
|
|
216
|
+
"length_squared",
|
|
217
|
+
"normalized",
|
|
218
|
+
"abs",
|
|
219
|
+
"sign",
|
|
220
|
+
"floor",
|
|
221
|
+
"ceil",
|
|
222
|
+
"round",
|
|
223
|
+
"is_normalized",
|
|
224
|
+
"is_zero_approx",
|
|
225
|
+
"is_finite",
|
|
226
|
+
"max_axis_index",
|
|
227
|
+
"min_axis_index",
|
|
228
|
+
"inverse",
|
|
229
|
+
],
|
|
230
|
+
TYPE_VECTOR4I: ["length", "length_squared", "abs", "sign", "max_axis_index", "min_axis_index"],
|
|
231
|
+
TYPE_COLOR: ["get_luminance", "inverted", "to_html"],
|
|
232
|
+
TYPE_RECT2: ["abs", "is_finite", "get_area", "get_center", "has_area"],
|
|
233
|
+
TYPE_RECT2I: ["abs", "get_area", "get_center", "has_area"],
|
|
234
|
+
TYPE_TRANSFORM2D:
|
|
235
|
+
[
|
|
236
|
+
"is_finite",
|
|
237
|
+
"get_origin",
|
|
238
|
+
"get_rotation",
|
|
239
|
+
"get_scale",
|
|
240
|
+
"get_skew",
|
|
241
|
+
"inverse",
|
|
242
|
+
"determinant",
|
|
243
|
+
"orthonormalized",
|
|
244
|
+
],
|
|
245
|
+
TYPE_TRANSFORM3D: ["is_finite", "inverse", "orthonormalized"],
|
|
246
|
+
TYPE_BASIS:
|
|
247
|
+
[
|
|
248
|
+
"is_finite",
|
|
249
|
+
"get_scale",
|
|
250
|
+
"inverse",
|
|
251
|
+
"determinant",
|
|
252
|
+
"orthonormalized",
|
|
253
|
+
"get_euler",
|
|
254
|
+
"get_rotation_quaternion",
|
|
255
|
+
],
|
|
256
|
+
TYPE_QUATERNION:
|
|
257
|
+
[
|
|
258
|
+
"length",
|
|
259
|
+
"length_squared",
|
|
260
|
+
"normalized",
|
|
261
|
+
"is_normalized",
|
|
262
|
+
"is_finite",
|
|
263
|
+
"inverse",
|
|
264
|
+
"get_euler",
|
|
265
|
+
"get_angle",
|
|
266
|
+
"get_axis",
|
|
267
|
+
],
|
|
268
|
+
TYPE_PLANE: ["normalized", "is_finite", "get_center"],
|
|
269
|
+
TYPE_AABB: ["abs", "is_finite", "get_center", "get_volume", "get_longest_axis", "get_shortest_axis"],
|
|
270
|
+
TYPE_PROJECTION: ["inverse", "determinant"],
|
|
271
|
+
}
|
|
69
272
|
## The calls an empty list has nothing to answer, which the engine reports as an error when asked.
|
|
70
273
|
const NEEDS_AN_ELEMENT: Array[String] = ["front", "back", "pick_random"]
|
|
71
274
|
|
|
@@ -97,7 +300,8 @@ const READS_ONLY: String = ", and a path, which a wait reads every frame, only c
|
|
|
97
300
|
##
|
|
98
301
|
## A step into a vector, a colour, a rectangle or a transform reads one of its components,
|
|
99
302
|
## "size:x" or "global_transform:origin:y", by the names GDScript gives them; see
|
|
100
|
-
## [method GdhSerialisation.components_of].
|
|
303
|
+
## [method GdhSerialisation.components_of]. It answers the calls in [constant VALUE_CALLS] too,
|
|
304
|
+
## "linear_velocity:length()".
|
|
101
305
|
##
|
|
102
306
|
## Answers with a `message` instead when a step along the way is not there or holds something that
|
|
103
307
|
## is not an object, naming the step rather than the whole path: "/root/Main:_game has no property
|
|
@@ -180,7 +384,53 @@ static func object_at(root: Node, node: Node, node_path: String, given: Variant)
|
|
|
180
384
|
## components can be walked into, and a number or a string is where a path ends whether the caller
|
|
181
385
|
## meant it to or not.
|
|
182
386
|
static func can_hold(value: Variant) -> bool:
|
|
183
|
-
return
|
|
387
|
+
return (
|
|
388
|
+
value is Object
|
|
389
|
+
or value is Array
|
|
390
|
+
or value is Dictionary
|
|
391
|
+
or packed(value)
|
|
392
|
+
or composite(value)
|
|
393
|
+
or textual(value)
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
## Whether [param value] is a string, which a path makes calls on and does not step into.
|
|
398
|
+
static func textual(value: Variant) -> bool:
|
|
399
|
+
return typeof(value) in [TYPE_STRING, TYPE_STRING_NAME]
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
## The calls a path makes on [param value], a packed list.
|
|
403
|
+
static func packed_calls(value: Variant) -> Array[String]:
|
|
404
|
+
var calls: Array[String] = PACKED_CALLS.duplicate()
|
|
405
|
+
if typeof(value) == TYPE_PACKED_BYTE_ARRAY:
|
|
406
|
+
calls.append_array(BYTE_CALLS)
|
|
407
|
+
else:
|
|
408
|
+
calls.append("to_byte_array")
|
|
409
|
+
return calls
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
## "changes" when [param method] is one of [param holder]'s own that changes it, "reads" when it is
|
|
413
|
+
## one that reads it given arguments, and "" otherwise. A packed list of bytes has more of both,
|
|
414
|
+
## encode_ and bswap changing it and decode_ reading it, which are told by their names.
|
|
415
|
+
static func container_method(holder: Variant, method: String) -> String:
|
|
416
|
+
var changes: Array[String] = MAP_CHANGES
|
|
417
|
+
var reads: Array[String] = MAP_READS
|
|
418
|
+
if holder is Array:
|
|
419
|
+
changes = LIST_CHANGES
|
|
420
|
+
reads = LIST_READS
|
|
421
|
+
elif packed(holder):
|
|
422
|
+
changes = PACKED_CHANGES
|
|
423
|
+
reads = PACKED_READS
|
|
424
|
+
if typeof(holder) == TYPE_PACKED_BYTE_ARRAY:
|
|
425
|
+
if method.begins_with("encode_") or method.begins_with("bswap"):
|
|
426
|
+
return "changes"
|
|
427
|
+
if method.begins_with("decode_") or method == "has_encoded_var":
|
|
428
|
+
return "reads"
|
|
429
|
+
if method in changes:
|
|
430
|
+
return "changes"
|
|
431
|
+
if method in reads:
|
|
432
|
+
return "reads"
|
|
433
|
+
return ""
|
|
184
434
|
|
|
185
435
|
|
|
186
436
|
## Whether [param value] is read by its components, a vector or a colour or a transform, and is a
|
|
@@ -189,6 +439,11 @@ static func composite(value: Variant) -> bool:
|
|
|
189
439
|
return not GdhSerialisation.components_of(value).is_empty()
|
|
190
440
|
|
|
191
441
|
|
|
442
|
+
## The calls a path makes on [param value], a vector, a colour, a rectangle or a transform.
|
|
443
|
+
static func value_calls(value: Variant) -> Array:
|
|
444
|
+
return VALUE_CALLS.get(typeof(value), [])
|
|
445
|
+
|
|
446
|
+
|
|
192
447
|
## Whether [param value] is a packed list. Stepped into the way a list is, by index, and a write into
|
|
193
448
|
## one reaches the game's own copy, since packed lists share their storage until one is duplicated.
|
|
194
449
|
static func packed(value: Variant) -> bool:
|
|
@@ -228,15 +483,19 @@ static func can_read(holder: Variant, named: String) -> bool:
|
|
|
228
483
|
return _index_in(named, items.size()) != -1
|
|
229
484
|
if packed(holder):
|
|
230
485
|
if not method.is_empty():
|
|
231
|
-
return args.is_empty() and method in
|
|
486
|
+
return args.is_empty() and method in packed_calls(holder)
|
|
232
487
|
return _index_in(named, len(holder)) != -1
|
|
488
|
+
if textual(holder):
|
|
489
|
+
return args.is_empty() and method in STRING_CALLS
|
|
233
490
|
if holder is Dictionary:
|
|
234
491
|
var map: Dictionary = holder
|
|
235
492
|
if not method.is_empty():
|
|
236
493
|
return args.is_empty() and method in MAP_CALLS
|
|
237
494
|
return not _key_in(map, named).is_empty()
|
|
238
495
|
if composite(holder):
|
|
239
|
-
|
|
496
|
+
if not method.is_empty():
|
|
497
|
+
return args.is_empty() and method in value_calls(holder)
|
|
498
|
+
return named in GdhSerialisation.components_of(holder)
|
|
240
499
|
if holder is Object:
|
|
241
500
|
var object: Object = holder
|
|
242
501
|
if not method.is_empty():
|
|
@@ -386,7 +645,7 @@ static func _not_literals(named: String) -> String:
|
|
|
386
645
|
## [method Object.has_method], because a method given too few or too many raises inside the game
|
|
387
646
|
## rather than answering.
|
|
388
647
|
static func _arity(object: Object, method: String) -> Dictionary:
|
|
389
|
-
for entry: Dictionary in
|
|
648
|
+
for entry: Dictionary in GdhValues.methods_of(object):
|
|
390
649
|
if str(entry.get("name", "")) != method:
|
|
391
650
|
continue
|
|
392
651
|
var params: Array = entry.get("args", [])
|
|
@@ -405,10 +664,13 @@ static func _arity(object: Object, method: String) -> Dictionary:
|
|
|
405
664
|
##
|
|
406
665
|
## A path is read, and a wait reads it every frame, so a call in one has to be a read. The engine
|
|
407
666
|
## marks its own reading methods const and `queue_free()`, `free()` and `set_name()` not, measured on
|
|
408
|
-
## 4.7.2
|
|
409
|
-
##
|
|
410
|
-
##
|
|
411
|
-
##
|
|
667
|
+
## 4.7.2, though it leaves some reads unmarked as well, `Engine.get_frames_drawn()` and
|
|
668
|
+
## `get_time_scale()` among them; so the refusal says the mark is missing, not that the method
|
|
669
|
+
## changes anything, and points at runtime_invoke call, which calls it. A game's methods carry no
|
|
670
|
+
## such mark, so one declared `-> void` is taken at its word, as doing something and answering
|
|
671
|
+
## nothing, and one left untyped is trusted. Without this a find with property "queue_free()" freed
|
|
672
|
+
## every node it matched, and a wait on "advance_day()" called it once a frame and then reported the
|
|
673
|
+
## state it had driven the game to.
|
|
412
674
|
##
|
|
413
675
|
## Given [param given] arguments, a call is the engine's and marked as reading, or it is refused. A
|
|
414
676
|
## game's method taking arguments is trusted on nothing at all: one answering a value can as well
|
|
@@ -450,7 +712,10 @@ static func call_refused(object: Object, method: String, called_as: String, give
|
|
|
450
712
|
)
|
|
451
713
|
return ""
|
|
452
714
|
if _native_flags(object, method) & METHOD_FLAG_CONST == 0:
|
|
453
|
-
return
|
|
715
|
+
return (
|
|
716
|
+
"%s.%s is not one the engine marks as only reading%s; runtime_invoke call calls it"
|
|
717
|
+
% [called_as, method, READS_ONLY]
|
|
718
|
+
)
|
|
454
719
|
return ""
|
|
455
720
|
|
|
456
721
|
|
|
@@ -459,15 +724,18 @@ static func call_refused(object: Object, method: String, called_as: String, give
|
|
|
459
724
|
## so they are offered only when one is near.
|
|
460
725
|
static func with_methods_offered(said: String, object: Object, method: String) -> String:
|
|
461
726
|
var own: Array[String] = []
|
|
462
|
-
var attached: Variant = object.get_script()
|
|
727
|
+
var attached: Variant = object if object is Script else object.get_script()
|
|
463
728
|
if attached is Script:
|
|
464
729
|
var script: Script = attached
|
|
465
730
|
for entry: Dictionary in script.get_script_method_list():
|
|
466
731
|
var name: String = str(entry.get("name", ""))
|
|
467
|
-
|
|
732
|
+
# A class called by its name runs only its static functions, so offering the rest leads to a refusal.
|
|
733
|
+
var flags: int = entry.get("flags", 0)
|
|
734
|
+
var callable: bool = not object is Script or flags & METHOD_FLAG_STATIC
|
|
735
|
+
if callable and not name.is_empty() and not own.has(name):
|
|
468
736
|
own.append(name)
|
|
469
737
|
var every: Array[String] = own.duplicate()
|
|
470
|
-
for entry: Dictionary in
|
|
738
|
+
for entry: Dictionary in GdhValues.methods_of(object):
|
|
471
739
|
var name: String = str(entry.get("name", ""))
|
|
472
740
|
if not every.has(name):
|
|
473
741
|
every.append(name)
|
|
@@ -477,7 +745,8 @@ static func with_methods_offered(said: String, object: Object, method: String) -
|
|
|
477
745
|
if own.is_empty():
|
|
478
746
|
return said
|
|
479
747
|
own.sort()
|
|
480
|
-
|
|
748
|
+
var offered: String = "its static functions are" if object is Script else "its script declares"
|
|
749
|
+
return "%s; %s %s" % [said, offered, ", ".join(PackedStringArray(own))]
|
|
481
750
|
|
|
482
751
|
|
|
483
752
|
## The entry a script attached to [param object] declares for [param method], or an empty one when
|
|
@@ -495,7 +764,7 @@ static func _script_method(object: Object, method: String) -> Dictionary:
|
|
|
495
764
|
|
|
496
765
|
## The flags the engine declares [param method] with on [param object].
|
|
497
766
|
static func _native_flags(object: Object, method: String) -> int:
|
|
498
|
-
for entry: Dictionary in
|
|
767
|
+
for entry: Dictionary in GdhValues.methods_of(object):
|
|
499
768
|
if str(entry.get("name", "")) == method:
|
|
500
769
|
var flags: int = entry.get("flags", 0)
|
|
501
770
|
return flags
|
|
@@ -563,7 +832,10 @@ static func write_back(chain: Array[Dictionary], changed: Variant) -> void:
|
|
|
563
832
|
## What [param holder] holds under [param named], or answers to it when [param named] is a call.
|
|
564
833
|
## Only ever called once [method can_read] agrees.
|
|
565
834
|
static func read_under(holder: Variant, named: String) -> Variant:
|
|
566
|
-
if (
|
|
835
|
+
if (
|
|
836
|
+
(holder is Array or holder is Dictionary or packed(holder) or composite(holder) or textual(holder))
|
|
837
|
+
and not method_of(named).is_empty()
|
|
838
|
+
):
|
|
567
839
|
return Callable.create(holder, method_of(named)).call()
|
|
568
840
|
if holder is Array:
|
|
569
841
|
var items: Array = holder
|
|
@@ -618,8 +890,17 @@ static func nothing_there(holder: Variant, named: String, called_as: String) ->
|
|
|
618
890
|
return "%s is a list of %d, so there is no %s in it" % [called_as, items.size(), named]
|
|
619
891
|
if packed(holder):
|
|
620
892
|
if not container_call.is_empty():
|
|
621
|
-
return container_calls_refused(
|
|
893
|
+
return container_calls_refused(
|
|
894
|
+
called_as, "a packed list", container_call, given_count, packed_calls(holder)
|
|
895
|
+
)
|
|
622
896
|
return "%s is a packed list of %d, so there is no %s in it" % [called_as, len(holder), named]
|
|
897
|
+
if textual(holder):
|
|
898
|
+
if container_call.is_empty():
|
|
899
|
+
return (
|
|
900
|
+
"%s is a string, so a path makes only calls on it, which read it and take no arguments: %s"
|
|
901
|
+
% [called_as, "(), ".join(STRING_CALLS) + "()"]
|
|
902
|
+
)
|
|
903
|
+
return container_calls_refused(called_as, "a string", container_call, given_count, STRING_CALLS)
|
|
623
904
|
if holder is Dictionary:
|
|
624
905
|
if not container_call.is_empty():
|
|
625
906
|
return container_calls_refused(called_as, "a map", container_call, given_count)
|
|
@@ -649,9 +930,21 @@ static func nothing_there(holder: Variant, named: String, called_as: String) ->
|
|
|
649
930
|
var sort: String = ("an " if kind.left(1) in ["A", "E", "I", "O", "U"] else "a ") + kind
|
|
650
931
|
var has: String = ", ".join(GdhSerialisation.components_of(holder))
|
|
651
932
|
if not container_call.is_empty():
|
|
933
|
+
var calls: Array = value_calls(holder)
|
|
934
|
+
if given_count > 0 and container_call in calls:
|
|
935
|
+
return (
|
|
936
|
+
"%s is %s, and a path calls %s() on one with no arguments"
|
|
937
|
+
% [called_as, sort, container_call]
|
|
938
|
+
)
|
|
939
|
+
var spelled: Array[String] = []
|
|
940
|
+
for each: Variant in calls:
|
|
941
|
+
spelled.append(str(each) + "()")
|
|
652
942
|
return (
|
|
653
|
-
|
|
654
|
-
|
|
943
|
+
(
|
|
944
|
+
"%s is %s, and %s() is not one of the calls a path makes on one, which read it"
|
|
945
|
+
+ " and take no arguments: %s; its components are %s"
|
|
946
|
+
)
|
|
947
|
+
% [called_as, sort, container_call, ", ".join(spelled), has]
|
|
655
948
|
)
|
|
656
949
|
return "%s is %s, so it has no %s; it has %s" % [called_as, sort, named, has]
|
|
657
950
|
if not holder is Object:
|
|
@@ -670,17 +963,17 @@ static func nothing_there(holder: Variant, named: String, called_as: String) ->
|
|
|
670
963
|
return GdhRead.near_property("%s has no property %s" % [called_as, named], object, named)
|
|
671
964
|
|
|
672
965
|
|
|
673
|
-
## Why [param method] is not a call a path makes on [param sort] ("a list"
|
|
674
|
-
##
|
|
675
|
-
## [param given] were.
|
|
966
|
+
## Why [param method] is not a call a path makes on [param sort] ("a list" or "a map", or another
|
|
967
|
+
## sort given its [param made]), naming the calls it does make, or that it makes this one with no
|
|
968
|
+
## arguments when [param given] were.
|
|
676
969
|
static func container_calls_refused(
|
|
677
|
-
called_as: String, sort: String, method: String, given: int = 0
|
|
970
|
+
called_as: String, sort: String, method: String, given: int = 0, made: Array[String] = []
|
|
678
971
|
) -> String:
|
|
679
972
|
var calls: Array[String] = MAP_CALLS
|
|
680
|
-
if
|
|
973
|
+
if not made.is_empty():
|
|
974
|
+
calls = made
|
|
975
|
+
elif sort == "a list":
|
|
681
976
|
calls = LIST_CALLS
|
|
682
|
-
elif sort == "a packed list":
|
|
683
|
-
calls = PACKED_CALLS
|
|
684
977
|
if given > 0 and method in calls:
|
|
685
978
|
return "%s is %s, and a path calls %s() on one with no arguments" % [called_as, sort, method]
|
|
686
979
|
var spelled: Array[String] = []
|