gdharness 1.2.41 → 1.3.0
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 +643 -378
- package/build/godot/addons/gdharness_editor/animation_reads.gd +7 -4
- package/build/godot/addons/gdharness_editor/bridge_client.gd +1 -1
- package/build/godot/addons/gdharness_editor/file_reads.gd +134 -10
- package/build/godot/addons/gdharness_editor/headless_check.gd +34 -4
- package/build/godot/addons/gdharness_editor/property_values.gd +4 -9
- package/build/godot/addons/gdharness_editor/reading.gd +25 -0
- package/build/godot/addons/gdharness_editor/scene_file.gd +209 -15
- package/build/godot/addons/gdharness_editor/serialisation.gd +5 -1
- package/build/godot/addons/gdharness_editor/tools/resource_tools.gd +9 -9
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd +346 -0
- package/build/godot/addons/gdharness_editor/tools/scene_kin.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd +438 -0
- package/build/godot/addons/gdharness_editor/tools/scene_paths.gd.uid +1 -0
- package/build/godot/addons/gdharness_editor/tools/scene_tools.gd +91 -49
- package/build/godot/addons/gdharness_runtime/reading.gd +25 -0
- package/build/godot/addons/gdharness_runtime/runtime_autoload.gd +2 -2
- package/build/godot/addons/gdharness_runtime/runtime_capture.gd +29 -0
- package/build/godot/addons/gdharness_runtime/runtime_input.gd +2 -7
- package/build/godot/addons/gdharness_runtime/runtime_mouse.gd +6 -14
- package/build/godot/addons/gdharness_runtime/serialisation.gd +5 -1
- package/build/godot/operations/animation_reads.gd +7 -4
- package/build/godot/operations/editor_tools.gd +19 -1
- package/build/godot/operations/file_reads.gd +134 -10
- package/build/godot/operations/property_values.gd +4 -9
- package/build/godot/operations/reading.gd +25 -0
- package/build/godot/operations/serialisation.gd +5 -1
- package/build/keeper.js +10 -4
- package/package.json +1 -2
- package/build/index.js +0 -45043
|
@@ -31,13 +31,26 @@ const HeadlessCheck = preload("headless_check.gd")
|
|
|
31
31
|
const PUTTING_BACK_PASSES: int = 4
|
|
32
32
|
const PropertyValues = preload("property_values.gd")
|
|
33
33
|
const Read = preload("reading.gd")
|
|
34
|
+
## The names Object.ConnectFlags gives each bit. The number alone left a reader guessing that 2 is
|
|
35
|
+
## the persistence every connection in a saved scene carries.
|
|
36
|
+
const CONNECT_FLAG_NAMES: Dictionary[int, String] = {
|
|
37
|
+
Object.CONNECT_DEFERRED: "deferred",
|
|
38
|
+
Object.CONNECT_PERSIST: "persist",
|
|
39
|
+
Object.CONNECT_ONE_SHOT: "one_shot",
|
|
40
|
+
Object.CONNECT_REFERENCE_COUNTED: "reference_counted",
|
|
41
|
+
Object.CONNECT_APPEND_SOURCE_OBJECT: "append_source_object",
|
|
42
|
+
}
|
|
34
43
|
|
|
35
44
|
## Whether a scan asked for through [method scan_later] is still to start, which a caller waiting
|
|
36
45
|
## for the editor's files to settle has to wait through as well.
|
|
37
46
|
static var scan_due: bool = false
|
|
47
|
+
## The files a headless save named by path alone because the uid cache holds no uid for them,
|
|
48
|
+
## gathered for the answer to the call that saved, the one call its engine runs.
|
|
49
|
+
static var by_path: PackedStringArray = []
|
|
38
50
|
|
|
39
51
|
var root: Node = null
|
|
40
52
|
var path: String = ""
|
|
53
|
+
## The path of each node a scene this one inherits gives, with the file that makes it.
|
|
41
54
|
var _base_paths: Dictionary = {}
|
|
42
55
|
var _state: SceneState = null
|
|
43
56
|
## What the file stores on each node it was opened with, by the node's instance id, so a node keeps
|
|
@@ -78,9 +91,16 @@ func open(scene_path: String, for_writing: bool) -> Dictionary:
|
|
|
78
91
|
return {"ok": false, "error": "Failed to instantiate " + path}
|
|
79
92
|
_state = packed.get_state()
|
|
80
93
|
var base: SceneState = _state.get_base_scene_state()
|
|
94
|
+
# Each node a base gives, with the file that makes it: the deepest base listing it as more than
|
|
95
|
+
# values set on a node from further down.
|
|
81
96
|
while base != null:
|
|
82
97
|
for index: int in base.get_node_count():
|
|
83
|
-
|
|
98
|
+
var given: String = _relative(str(base.get_node_path(index)))
|
|
99
|
+
var made: bool = (
|
|
100
|
+
base.get_node_instance(index) != null or not str(base.get_node_type(index)).is_empty()
|
|
101
|
+
)
|
|
102
|
+
if made or not _base_paths.has(given):
|
|
103
|
+
_base_paths[given] = base.get_path()
|
|
84
104
|
base = base.get_base_scene_state()
|
|
85
105
|
# On a read as well, which would otherwise answer what the scripts set as what the file holds.
|
|
86
106
|
if not Engine.is_editor_hint():
|
|
@@ -123,6 +143,13 @@ func asked(node: Node, names: Array) -> void:
|
|
|
123
143
|
_reached.merge(HeadlessCheck.reached(node, property))
|
|
124
144
|
|
|
125
145
|
|
|
146
|
+
## Takes [param resource], built into the scene, as one the tool changed, which a write saves as it is.
|
|
147
|
+
func reached_into(resource: Resource) -> void:
|
|
148
|
+
var id: String = resource.get_scene_unique_id()
|
|
149
|
+
if not id.is_empty():
|
|
150
|
+
_reached[id] = true
|
|
151
|
+
|
|
152
|
+
|
|
126
153
|
## Takes each copy in [param copies], keyed by the node it was made from, as holding what that node's
|
|
127
154
|
## file entry holds.
|
|
128
155
|
func copied(copies: Dictionary) -> void:
|
|
@@ -151,12 +178,45 @@ func refuse(error: String) -> Dictionary:
|
|
|
151
178
|
return {"ok": false, "error": error}
|
|
152
179
|
|
|
153
180
|
|
|
181
|
+
## Each bit set in [param flags], a connection's, by name, and whatever bits are left unnamed as one
|
|
182
|
+
## number.
|
|
183
|
+
static func flag_names(flags: int) -> Array[String]:
|
|
184
|
+
var names: Array[String] = []
|
|
185
|
+
var rest: int = flags
|
|
186
|
+
for bit: int in CONNECT_FLAG_NAMES:
|
|
187
|
+
if flags & bit:
|
|
188
|
+
names.append(CONNECT_FLAG_NAMES[bit])
|
|
189
|
+
rest &= ~bit
|
|
190
|
+
if rest != 0:
|
|
191
|
+
names.append(str(rest))
|
|
192
|
+
return names
|
|
193
|
+
|
|
194
|
+
|
|
154
195
|
## [param said], the refusal for [param node_path] found nowhere in this scene, with how a path is
|
|
155
|
-
## read when it starts with the root's own name
|
|
196
|
+
## read when it starts with the root's own name, and otherwise with the last node of the path the
|
|
197
|
+
## scene has and what is under it, as after a node was moved or renamed.
|
|
156
198
|
func not_found(said: String, node_path: String) -> String:
|
|
157
|
-
if root == null
|
|
199
|
+
if root == null:
|
|
200
|
+
return said
|
|
201
|
+
if not root.has_node(NodePath(node_path.get_slice("/", 0))):
|
|
202
|
+
var hinted: String = Read.from_the_root(said, node_path, str(root.name))
|
|
203
|
+
if hinted != said:
|
|
204
|
+
return hinted
|
|
205
|
+
var parts: PackedStringArray = node_path.trim_prefix("./").split("/", false)
|
|
206
|
+
var at: Node = root
|
|
207
|
+
var reached: PackedStringArray = []
|
|
208
|
+
for part: String in parts:
|
|
209
|
+
var below: Node = at.get_node_or_null(NodePath(part))
|
|
210
|
+
if below == null:
|
|
211
|
+
break
|
|
212
|
+
at = below
|
|
213
|
+
var _walked: bool = reached.append(part)
|
|
214
|
+
if reached.size() >= parts.size():
|
|
158
215
|
return said
|
|
159
|
-
|
|
216
|
+
var names: PackedStringArray = []
|
|
217
|
+
for child: Node in at.get_children():
|
|
218
|
+
var _named: bool = names.append(str(child.name))
|
|
219
|
+
return Read.missing_below(said, str(root.name), reached, parts[reached.size()], names)
|
|
160
220
|
|
|
161
221
|
|
|
162
222
|
func close() -> void:
|
|
@@ -165,6 +225,27 @@ func close() -> void:
|
|
|
165
225
|
root = null
|
|
166
226
|
|
|
167
227
|
|
|
228
|
+
## What the file holds under the instance at [param at] that goes once its children are not
|
|
229
|
+
## editable, as {values, nodes}: the paths of the instance's nodes it sets values on, which stay with
|
|
230
|
+
## the instance's own values, and of the nodes the scene added below one of them, which are gone,
|
|
231
|
+
## since the packer skips everything below a node of an instance that is not editable. A node added
|
|
232
|
+
## straight under [param at] is the scene's own and stays.
|
|
233
|
+
func held_under(at: String) -> Dictionary:
|
|
234
|
+
var values: Array[String] = []
|
|
235
|
+
var nodes: Array[String] = []
|
|
236
|
+
for index: int in _state.get_node_count():
|
|
237
|
+
var entry: String = _relative(str(_state.get_node_path(index)))
|
|
238
|
+
var parent: String = _relative(str(_state.get_node_path(index, true)))
|
|
239
|
+
var values_only: bool = (
|
|
240
|
+
_state.get_node_instance(index) == null and str(_state.get_node_type(index)).is_empty()
|
|
241
|
+
)
|
|
242
|
+
if values_only and entry.begins_with(at + "/"):
|
|
243
|
+
values.append(entry)
|
|
244
|
+
elif not values_only and parent.begins_with(at + "/"):
|
|
245
|
+
nodes.append(entry)
|
|
246
|
+
return {"values": values, "nodes": nodes}
|
|
247
|
+
|
|
248
|
+
|
|
168
249
|
## The path of [param node] as a tool names it: "." for the root.
|
|
169
250
|
func path_of(node: Node) -> String:
|
|
170
251
|
return str(root.get_path_to(node))
|
|
@@ -175,16 +256,46 @@ func path_of(node: Node) -> String:
|
|
|
175
256
|
func foreign(node: Node) -> String:
|
|
176
257
|
if node == root or node.owner == root:
|
|
177
258
|
return ""
|
|
178
|
-
if node.owner
|
|
259
|
+
if node.owner == null:
|
|
260
|
+
return (
|
|
261
|
+
"%s is made by a script as the scene is instanced, and no scene file saves anything about it."
|
|
262
|
+
% path_of(node)
|
|
263
|
+
)
|
|
264
|
+
if root.is_editable_instance(node.owner):
|
|
179
265
|
return ""
|
|
180
|
-
var
|
|
181
|
-
return (
|
|
266
|
+
var said: String = (
|
|
182
267
|
(
|
|
183
268
|
"%s belongs to the scene instanced at %s (%s), and this scene saves nothing about it. Edit "
|
|
184
|
-
+ "that scene instead
|
|
269
|
+
+ "that scene instead, which changes every instance of it"
|
|
185
270
|
)
|
|
186
|
-
% [path_of(node),
|
|
271
|
+
% [path_of(node), path_of(node.owner), node.owner.scene_file_path]
|
|
187
272
|
)
|
|
273
|
+
var steps: PackedStringArray = []
|
|
274
|
+
for closed: String in _closed_around(node):
|
|
275
|
+
var _added: bool = steps.append("nodePath %s editableChildren true" % closed)
|
|
276
|
+
if steps.is_empty():
|
|
277
|
+
return said + "."
|
|
278
|
+
return (
|
|
279
|
+
said
|
|
280
|
+
+ ", or have this scene keep its own values for this instance with scene_node set "
|
|
281
|
+
+ ", then ".join(steps)
|
|
282
|
+
+ "."
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
## The instances around [param node] whose children are not editable, outermost first: each must be
|
|
287
|
+
## made editable, in that order, before this scene keeps values of its own for [param node], since
|
|
288
|
+
## the packer skips every node under an instance that is not. Empty when nothing would let it.
|
|
289
|
+
func _closed_around(node: Node) -> PackedStringArray:
|
|
290
|
+
var closed: PackedStringArray = []
|
|
291
|
+
var instance: Node = node.owner
|
|
292
|
+
while instance != root:
|
|
293
|
+
if instance == null:
|
|
294
|
+
return []
|
|
295
|
+
if not root.is_editable_instance(instance):
|
|
296
|
+
var _at: int = closed.insert(0, path_of(instance))
|
|
297
|
+
instance = instance.owner
|
|
298
|
+
return closed
|
|
188
299
|
|
|
189
300
|
|
|
190
301
|
## Why [param node] cannot be moved, renamed, copied or deleted, or "": the scene may only
|
|
@@ -201,10 +312,10 @@ func fixed(node: Node) -> String:
|
|
|
201
312
|
if _base_paths.has(at):
|
|
202
313
|
return (
|
|
203
314
|
(
|
|
204
|
-
"%s
|
|
315
|
+
"%s is made by %s, a scene %s inherits, which creates it again on load. Edit that "
|
|
205
316
|
+ "scene instead."
|
|
206
317
|
)
|
|
207
|
-
% [at, path]
|
|
318
|
+
% [at, _base_paths[at], path]
|
|
208
319
|
)
|
|
209
320
|
return ""
|
|
210
321
|
|
|
@@ -332,10 +443,25 @@ func unusable_name(parent: Node, child_name: String, moving: Node = null) -> Str
|
|
|
332
443
|
|
|
333
444
|
## The names of the properties this scene's own file sets on [param node], whatever their values.
|
|
334
445
|
func set_here(node: Node) -> Dictionary:
|
|
446
|
+
return set_at(path_of(node))
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
## Where the values of [param node], at [param at] in the file, come from when the file does not set
|
|
450
|
+
## them: "" for a node this scene makes, which holds them all, or the scene that makes the node, the
|
|
451
|
+
## one it is instanced from or one this scene inherits.
|
|
452
|
+
func values_from(node: Node, at: String) -> String:
|
|
453
|
+
if node != root and not node.scene_file_path.is_empty():
|
|
454
|
+
return node.scene_file_path
|
|
455
|
+
if node != root and node.owner != root:
|
|
456
|
+
return node.owner.scene_file_path if node.owner != null else ""
|
|
457
|
+
return str(_base_paths.get(at, ""))
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
## The names of the properties this scene's own file sets on the node at [param at].
|
|
461
|
+
func set_at(at: String) -> Dictionary:
|
|
335
462
|
var names: Dictionary = {}
|
|
336
463
|
if _state == null:
|
|
337
464
|
return names
|
|
338
|
-
var at: String = path_of(node)
|
|
339
465
|
for index: int in _state.get_node_count():
|
|
340
466
|
if _relative(str(_state.get_node_path(index))) != at:
|
|
341
467
|
continue
|
|
@@ -447,17 +573,85 @@ static func save_packed(packed: PackedScene, scene_path: String) -> Dictionary:
|
|
|
447
573
|
static func save_keeping_uid(resource: Resource, file_path: String) -> Error:
|
|
448
574
|
if Engine.is_editor_hint():
|
|
449
575
|
return ResourceSaver.save(resource, file_path)
|
|
450
|
-
var uid: int =
|
|
576
|
+
var uid: int = uid_in(file_path)
|
|
451
577
|
var saving: Error = ResourceSaver.save(resource, file_path)
|
|
452
578
|
if saving != OK:
|
|
453
579
|
return saving
|
|
454
580
|
if uid == ResourceUID.INVALID_ID:
|
|
455
581
|
uid = ResourceUID.create_id()
|
|
456
|
-
|
|
582
|
+
var marked: Error = ResourceSaver.set_uid(file_path, uid)
|
|
583
|
+
if marked != OK:
|
|
584
|
+
return marked
|
|
585
|
+
return _with_external_uids(file_path)
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
## Puts back the uid on each external resource the text file at [param file_path] names. Only the
|
|
589
|
+
## editor's file system tells the saver a path's uid, so a headless save writes every reference by
|
|
590
|
+
## path alone, and each breaks when the file it names is moved.
|
|
591
|
+
static func _with_external_uids(file_path: String) -> Error:
|
|
592
|
+
if not (file_path.ends_with(".tscn") or file_path.ends_with(".tres")):
|
|
593
|
+
return OK
|
|
594
|
+
var lines: PackedStringArray = FileAccess.get_file_as_string(file_path).split("\n")
|
|
595
|
+
var pattern: RegEx = RegEx.create_from_string(' path="([^"]+)"')
|
|
596
|
+
var changed: bool = false
|
|
597
|
+
for at: int in lines.size():
|
|
598
|
+
var line: String = lines[at]
|
|
599
|
+
if not line.begins_with("[ext_resource ") or line.contains(' uid="'):
|
|
600
|
+
continue
|
|
601
|
+
var named: RegExMatch = pattern.search(line)
|
|
602
|
+
if named == null:
|
|
603
|
+
continue
|
|
604
|
+
var uid: String = reference_uid(named.get_string(1))
|
|
605
|
+
if not uid.is_empty():
|
|
606
|
+
lines[at] = line.replace(' path="', uid + ' path="')
|
|
607
|
+
changed = true
|
|
608
|
+
if not changed:
|
|
609
|
+
return OK
|
|
610
|
+
var file: FileAccess = FileAccess.open(file_path, FileAccess.WRITE)
|
|
611
|
+
if file == null:
|
|
612
|
+
return FileAccess.get_open_error()
|
|
613
|
+
if not file.store_string("\n".join(lines)):
|
|
614
|
+
return ERR_FILE_CANT_WRITE
|
|
615
|
+
file.close()
|
|
616
|
+
return OK
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
## [method uid_attribute] for a reference about to be written, noting [param named] under
|
|
620
|
+
## [member by_path] when it is left to be named by path.
|
|
621
|
+
static func reference_uid(named: String) -> String:
|
|
622
|
+
var uid: String = uid_attribute(named)
|
|
623
|
+
if uid.is_empty():
|
|
624
|
+
note_by_path(named)
|
|
625
|
+
return uid
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
## Notes [param named], a reference just written by path alone, under [member by_path] when the uid
|
|
629
|
+
## cache holds nothing for it: a file made since the project was last scanned, whose uid the cache
|
|
630
|
+
## learns from the next scan. Not a file whose uid the cache gives to another, which a scan leaves.
|
|
631
|
+
static func note_by_path(named: String) -> void:
|
|
632
|
+
if Engine.is_editor_hint() or not FileAccess.file_exists(named) or by_path.has(named):
|
|
633
|
+
return
|
|
634
|
+
var own: int = uid_in(named)
|
|
635
|
+
if own == ResourceUID.INVALID_ID and FileAccess.file_exists(named + ".uid"):
|
|
636
|
+
own = ResourceUID.text_to_id(FileAccess.get_file_as_string(named + ".uid").strip_edges())
|
|
637
|
+
if own == ResourceUID.INVALID_ID or not ResourceUID.has_id(own):
|
|
638
|
+
var _noted: bool = by_path.append(named)
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
## The uid attribute a reference to [param named] is written with, as ' uid="uid://..."', or "".
|
|
642
|
+
##
|
|
643
|
+
## Only a uid the uid cache gives that path, which is what the loader resolves it by. A uid the cache
|
|
644
|
+
## does not know (a file made with no editor since the last scan) is answered with a warning on every
|
|
645
|
+
## load, and one it gives another file (a scene copied whole keeps its original's) loads that file.
|
|
646
|
+
static func uid_attribute(named: String) -> String:
|
|
647
|
+
var id: int = ResourceLoader.get_resource_uid(named)
|
|
648
|
+
if id == ResourceUID.INVALID_ID or not ResourceUID.has_id(id) or ResourceUID.get_id_path(id) != named:
|
|
649
|
+
return ""
|
|
650
|
+
return ' uid="%s"' % ResourceUID.id_to_text(id)
|
|
457
651
|
|
|
458
652
|
|
|
459
653
|
## The uid the file at [param file_path] declares, or [constant ResourceUID.INVALID_ID].
|
|
460
|
-
static func
|
|
654
|
+
static func uid_in(file_path: String) -> int:
|
|
461
655
|
if not FileAccess.file_exists(file_path):
|
|
462
656
|
return ResourceUID.INVALID_ID
|
|
463
657
|
var file: FileAccess = FileAccess.open(file_path, FileAccess.READ)
|
|
@@ -664,8 +664,12 @@ func _serialize_array(value: Array) -> Array:
|
|
|
664
664
|
|
|
665
665
|
# Base64 rather than a list of numbers. A byte array is a texture, a sound or a save file often
|
|
666
666
|
# enough that the list would be the whole answer, megabytes of it, and unreadable either way.
|
|
667
|
+
#
|
|
668
|
+
# The engine's encoder raises an error on an empty array, and an empty tile_map_data is every
|
|
669
|
+
# TileMapLayer with nothing painted yet, so a read of one carried an engine error in its answer.
|
|
667
670
|
func _serialize_bytes(value: PackedByteArray) -> Dictionary:
|
|
668
|
-
|
|
671
|
+
var text: String = "" if value.is_empty() else Marshalls.raw_to_base64(value)
|
|
672
|
+
return {"base64": text, "size": value.size(), "_type": "PackedByteArray"}
|
|
669
673
|
|
|
670
674
|
|
|
671
675
|
# The packed vector and colour arrays, each element serialised the way one of them on its own is.
|
|
@@ -304,10 +304,10 @@ func read_resource(args: Dictionary) -> Dictionary:
|
|
|
304
304
|
|
|
305
305
|
|
|
306
306
|
func create_shader(args: Dictionary) -> Dictionary:
|
|
307
|
-
var shader_path: String = _ensure_res_path(str(args.get("
|
|
307
|
+
var shader_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
308
308
|
var shader_type: String = str(args.get("shaderType", "canvas_item"))
|
|
309
309
|
if shader_path == "res://":
|
|
310
|
-
return {"ok": false, "error": "
|
|
310
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
311
311
|
var taken: String = _taken(shader_path, "resource_edit op=create_shader", "Edit its text")
|
|
312
312
|
if not taken.is_empty():
|
|
313
313
|
return {"ok": false, "error": taken}
|
|
@@ -336,9 +336,9 @@ func create_shader(args: Dictionary) -> Dictionary:
|
|
|
336
336
|
|
|
337
337
|
|
|
338
338
|
func create_tileset(args: Dictionary) -> Dictionary:
|
|
339
|
-
var tileset_path: String = _ensure_res_path(str(args.get("
|
|
339
|
+
var tileset_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
340
340
|
if tileset_path == "res://":
|
|
341
|
-
return {"ok": false, "error": "
|
|
341
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
342
342
|
var taken: String = _taken(tileset_path, "resource_edit op=create_tileset")
|
|
343
343
|
if not taken.is_empty():
|
|
344
344
|
return {"ok": false, "error": taken}
|
|
@@ -478,7 +478,7 @@ func _source_ids(tile_set: TileSet) -> Array[int]:
|
|
|
478
478
|
|
|
479
479
|
func set_tilemap_cells(args: Dictionary) -> Dictionary:
|
|
480
480
|
var scene_path: String = _ensure_res_path(str(args.get("scenePath", "")))
|
|
481
|
-
var node_path: String = str(args.get("
|
|
481
|
+
var node_path: String = str(args.get("nodePath", ""))
|
|
482
482
|
if scene_path == "res://":
|
|
483
483
|
return {"ok": false, "error": "scenePath is required"}
|
|
484
484
|
|
|
@@ -702,9 +702,9 @@ func _save_theme(theme: Theme, theme_path: String, item: String) -> String:
|
|
|
702
702
|
|
|
703
703
|
|
|
704
704
|
func set_theme_color(args: Dictionary) -> Dictionary:
|
|
705
|
-
var theme_path: String = _ensure_res_path(str(args.get("
|
|
705
|
+
var theme_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
706
706
|
if theme_path == "res://":
|
|
707
|
-
return {"ok": false, "error": "
|
|
707
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
708
708
|
|
|
709
709
|
var color_name: String = str(args.get("colorName", ""))
|
|
710
710
|
var control_type: String = str(args.get("controlType", ""))
|
|
@@ -745,9 +745,9 @@ func set_theme_color(args: Dictionary) -> Dictionary:
|
|
|
745
745
|
|
|
746
746
|
|
|
747
747
|
func set_theme_font_size(args: Dictionary) -> Dictionary:
|
|
748
|
-
var theme_path: String = _ensure_res_path(str(args.get("
|
|
748
|
+
var theme_path: String = _ensure_res_path(str(args.get("resourcePath", "")))
|
|
749
749
|
if theme_path == "res://":
|
|
750
|
-
return {"ok": false, "error": "
|
|
750
|
+
return {"ok": false, "error": "resourcePath is required"}
|
|
751
751
|
|
|
752
752
|
var font_size_name: String = str(args.get("fontSizeName", ""))
|
|
753
753
|
var control_type: String = str(args.get("controlType", ""))
|