breakpoint-mcp 1.82.1 → 1.83.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/addon/breakpoint_mcp/operations.gd +298 -275
- package/addon/breakpoint_mcp/plugin.cfg +1 -1
- package/addon/breakpoint_mcp/runtime_bridge.gd +20 -3
- package/dist/addon-version.js.map +1 -0
- package/dist/annotations.js.map +1 -0
- package/dist/bridge.js +86 -2
- package/dist/bridge.js.map +1 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/clients.js.map +1 -0
- package/dist/cli/doctor.js +147 -6
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/github.js.map +1 -0
- package/dist/cli/init.js +26 -4
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/tools.js.map +1 -0
- package/dist/cli/usage.js +40 -1
- package/dist/cli/usage.js.map +1 -0
- package/dist/close-cause.js.map +1 -0
- package/dist/config.js.map +1 -0
- package/dist/confirm.js +13 -21
- package/dist/confirm.js.map +1 -0
- package/dist/connect-cause.js.map +1 -0
- package/dist/csdap.js.map +1 -0
- package/dist/cslsp.js.map +1 -0
- package/dist/dap.js.map +1 -0
- package/dist/exit-cause.js.map +1 -0
- package/dist/finiteness.js.map +1 -0
- package/dist/framing.js.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/late-reply.js.map +1 -0
- package/dist/logger.js.map +1 -0
- package/dist/lsp.js.map +1 -0
- package/dist/mutation-guard.js +235 -0
- package/dist/mutation-guard.js.map +1 -0
- package/dist/path-cohort.js.map +1 -0
- package/dist/paths.js.map +1 -0
- package/dist/pause.js.map +1 -0
- package/dist/peers.js +10 -3
- package/dist/peers.js.map +1 -0
- package/dist/ports.js.map +1 -0
- package/dist/readiness.js.map +1 -0
- package/dist/recipes.js.map +1 -0
- package/dist/remedies.js.map +1 -0
- package/dist/result-cost.js.map +1 -0
- package/dist/schemas.js +123 -46
- package/dist/schemas.js.map +1 -0
- package/dist/secret.js.map +1 -0
- package/dist/spawn-guard.js +76 -0
- package/dist/spawn-guard.js.map +1 -0
- package/dist/stdio.js.map +1 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/tasks.js.map +1 -0
- package/dist/timeout-cause.js.map +1 -0
- package/dist/timeout-caveat.js.map +1 -0
- package/dist/tools/assetgen.js +13 -7
- package/dist/tools/assetgen.js.map +1 -0
- package/dist/tools/backend.js +4 -0
- package/dist/tools/backend.js.map +1 -0
- package/dist/tools/cli.js +62 -19
- package/dist/tools/cli.js.map +1 -0
- package/dist/tools/csdap.js.map +1 -0
- package/dist/tools/cslsp.js.map +1 -0
- package/dist/tools/dap.js.map +1 -0
- package/dist/tools/editor/animation.js +3 -3
- package/dist/tools/editor/animation.js.map +1 -0
- package/dist/tools/editor/audio.js +5 -3
- package/dist/tools/editor/audio.js.map +1 -0
- package/dist/tools/editor/common.js.map +1 -0
- package/dist/tools/editor/core.js.map +1 -0
- package/dist/tools/editor/filesystem.js.map +1 -0
- package/dist/tools/editor/introspection.js.map +1 -0
- package/dist/tools/editor/node.js +4 -4
- package/dist/tools/editor/node.js.map +1 -0
- package/dist/tools/editor/particles.js +2 -1
- package/dist/tools/editor/particles.js.map +1 -0
- package/dist/tools/editor/physics.js +5 -4
- package/dist/tools/editor/physics.js.map +1 -0
- package/dist/tools/editor/project_input_test.js.map +1 -0
- package/dist/tools/editor/resource.js +11 -6
- package/dist/tools/editor/resource.js.map +1 -0
- package/dist/tools/editor/scene.js +7 -4
- package/dist/tools/editor/scene.js.map +1 -0
- package/dist/tools/editor/shader.js +4 -3
- package/dist/tools/editor/shader.js.map +1 -0
- package/dist/tools/editor/signal.js.map +1 -0
- package/dist/tools/editor/spatial.js +15 -8
- package/dist/tools/editor/spatial.js.map +1 -0
- package/dist/tools/editor/tiles.js +5 -3
- package/dist/tools/editor/tiles.js.map +1 -0
- package/dist/tools/editor/ui.js +6 -4
- package/dist/tools/editor/ui.js.map +1 -0
- package/dist/tools/editor.js.map +1 -0
- package/dist/tools/knowledge.js.map +1 -0
- package/dist/tools/lsp-common.js.map +1 -0
- package/dist/tools/lsp.js.map +1 -0
- package/dist/tools/netcode.js +6 -5
- package/dist/tools/netcode.js.map +1 -0
- package/dist/tools/processes.js +28 -8
- package/dist/tools/processes.js.map +1 -0
- package/dist/tools/resources.js.map +1 -0
- package/dist/tools/runtime.js +2 -1
- package/dist/tools/runtime.js.map +1 -0
- package/dist/tools/tabletop.js +49 -23
- package/dist/tools/tabletop.js.map +1 -0
- package/dist/tools/vcs.js +21 -3
- package/dist/tools/vcs.js.map +1 -0
- package/dist/toolsets.js.map +1 -0
- package/dist/version.js.map +1 -0
- package/dist/wire-defaults.js.map +1 -0
- package/package.json +2 -1
|
@@ -8,7 +8,7 @@ extends RefCounted
|
|
|
8
8
|
|
|
9
9
|
const Codec := preload("res://addons/breakpoint_mcp/variant_json.gd")
|
|
10
10
|
const Remedies := preload("res://addons/breakpoint_mcp/error_remedies.gd")
|
|
11
|
-
const ADDON_VERSION := "1.
|
|
11
|
+
const ADDON_VERSION := "1.15.0"
|
|
12
12
|
|
|
13
13
|
var _plugin: EditorPlugin
|
|
14
14
|
|
|
@@ -373,6 +373,101 @@ func _path_of(root: Node, node: Node) -> String:
|
|
|
373
373
|
return String(root.get_path_to(node))
|
|
374
374
|
|
|
375
375
|
|
|
376
|
+
## THE ONE PLACE A NODE JOINS THE EDITED SCENE.
|
|
377
|
+
##
|
|
378
|
+
## 🔴 `force_readable_name = true` IS LOAD-BEARING, NOT COSMETIC. Left at Godot's
|
|
379
|
+
## default of false — which is what all twenty-two authoring tools did before 283 —
|
|
380
|
+
## the engine answers ANY name collision with the machine form `@Type@N`, a name no
|
|
381
|
+
## caller asked for and no human reads. Measured on 4.7: `node_add {name: "SFX"}`
|
|
382
|
+
## twice returned "SFX" and then "@AudioStreamPlayer3D@19825", with no error and no
|
|
383
|
+
## flag, so the caller's next call addressing "SFX" got `bad_path`. `node_duplicate`
|
|
384
|
+
## had NO non-colliding case at all — a duplicate always collides with its source,
|
|
385
|
+
## so "@Label@19826" was that tool's ONLY behaviour, where the editor's own Duplicate
|
|
386
|
+
## gives "Label2". With `true` the engine takes the readable path the editor's Add
|
|
387
|
+
## Node and Duplicate take, and the host's shipped promise that a name "defaults to
|
|
388
|
+
## the class name" is true for the first time.
|
|
389
|
+
##
|
|
390
|
+
## 🔵 AND THE RENAME IS REPORTED, BECAUSE "SFX2" IS STILL NOT WHAT WAS ASKED FOR.
|
|
391
|
+
## The returned Dictionary carries `coerced: true` and `requested` whenever the
|
|
392
|
+
## engine's name differs — the shape `node_set_property` has answered with since
|
|
393
|
+
## 1.82.0, so a caller parses one convention rather than two. `requested` is read
|
|
394
|
+
## off the node itself rather than passed in, so a site cannot report a name it did
|
|
395
|
+
## not actually ask the engine for.
|
|
396
|
+
##
|
|
397
|
+
## 🔴 A BARE `add_child` IN AN AUTHORING HANDLER IS THE DEFECT AGAIN, so this is the
|
|
398
|
+
## only registration site in this file and `contract_check.py` check 31 refuses a
|
|
399
|
+
## second one. A twenty-third authoring tool is covered by USING the seam, not by
|
|
400
|
+
## somebody remembering the flag.
|
|
401
|
+
func _commit_add(node: Node, parent: Node, root: Node, action: String, also_own: Array = []) -> Dictionary:
|
|
402
|
+
var requested := String(node.name)
|
|
403
|
+
var ur := _plugin.get_undo_redo()
|
|
404
|
+
ur.create_action(action)
|
|
405
|
+
ur.add_do_method(parent, "add_child", node, true)
|
|
406
|
+
ur.add_do_method(node, "set_owner", root)
|
|
407
|
+
for d in also_own:
|
|
408
|
+
ur.add_do_method(d, "set_owner", root)
|
|
409
|
+
ur.add_do_reference(node)
|
|
410
|
+
ur.add_undo_method(parent, "remove_child", node)
|
|
411
|
+
ur.commit_action()
|
|
412
|
+
var actual := String(node.name)
|
|
413
|
+
var out := {"path": _path_of(root, node), "name": actual}
|
|
414
|
+
if actual != requested:
|
|
415
|
+
out["coerced"] = true
|
|
416
|
+
out["requested"] = requested
|
|
417
|
+
return out
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
## 🆕 284 — THE ONE PLACE THIS FILE WRITES A RESOURCE TO DISK.
|
|
421
|
+
##
|
|
422
|
+
## 🔴 MEASURED FROM A USER'S SIDE AGAINST A LIVE GODOT 4.7, AND IT IS 283 §1 ONE AXIS
|
|
423
|
+
## OVER. 283 found that every tool taking a `name` handed it to `add_child` with
|
|
424
|
+
## `force_readable_name` defaulted false, so a collision came back as `@Type@N` with no
|
|
425
|
+
## flag. The collision here is a FILE and the answer was DELETION. Nine resources were
|
|
426
|
+
## created, a sentinel line appended to each on disk, and each tool called a SECOND time
|
|
427
|
+
## with identical arguments: every sentinel was gone, and every reply read `created` /
|
|
428
|
+
## `saved` / `packed` — the same words, in the same shape, as the first call.
|
|
429
|
+
##
|
|
430
|
+
## `resource_create` overwrote an Environment a property had been set on, resetting it;
|
|
431
|
+
## asked for a StandardMaterial3D at the same path it silently turned that resource into
|
|
432
|
+
## a material, so anything referencing it as an Environment now holds the wrong type.
|
|
433
|
+
## `scene_new` replaced a saved scene on disk while the editor's open copy still held the
|
|
434
|
+
## node that had been added, so file and editor disagree and nothing says so.
|
|
435
|
+
##
|
|
436
|
+
## 🔴 AND THE PRODUCT GAVE FOUR ANSWERS TO ONE QUESTION. `filesystem_move` refused
|
|
437
|
+
## `exists` with no way to force; the seven scaffold tools under `_mp_write_script`
|
|
438
|
+
## refused `exists` unless `overwrite`; `filesystem_create_dir` succeeded and reported
|
|
439
|
+
## `existed`; and the rest destroyed silently. `_mp_write_script` was already right, and
|
|
440
|
+
## it was right because it is a SEAM — one function, one answer, seven tools. This is
|
|
441
|
+
## that function for the twenty-four `ResourceSaver.save` sites, which were a roster:
|
|
442
|
+
## 282 §2.3's rule, paid on a second uncounted population one session after the first.
|
|
443
|
+
##
|
|
444
|
+
## 🔵 THE TWO KINDS ARE A PROPERTY OF THE CALL SITE, NOT OF THE CALLER'S ARGUMENTS, and
|
|
445
|
+
## that distinction is the whole design. `SAVE_NEW` means `to_path` is a DESTINATION the
|
|
446
|
+
## caller named — a collision there is somebody else's file. `SAVE_BACK` means the path
|
|
447
|
+
## is the resource's own home, loaded a few lines above and written back: overwriting is
|
|
448
|
+
## not a hazard there, it IS the operation, and refusing it would break every
|
|
449
|
+
## `*_set_property` tool on the surface. A flag the CALLER could set would let a caller
|
|
450
|
+
## turn `theme_set_color` into a refusal; a constant at the SITE cannot.
|
|
451
|
+
##
|
|
452
|
+
## 🔵 `replaced` IS REPORTED ONLY WHEN IT HAPPENED — the shape `node_set_property` has
|
|
453
|
+
## carried since 1.82.0 and `_commit_add` since 283: a field that appears when the engine
|
|
454
|
+
## did something other than the plain thing, and is absent otherwise. *I created a file*
|
|
455
|
+
## and *I overwrote your file because you asked me to* are not the same sentence.
|
|
456
|
+
const SAVE_NEW := 0
|
|
457
|
+
const SAVE_BACK := 1
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
func _commit_save(res: Resource, to_path: String, params: Dictionary, kind: int,
|
|
461
|
+
flags: int = 0) -> Dictionary:
|
|
462
|
+
var existed := FileAccess.file_exists(to_path)
|
|
463
|
+
if kind == SAVE_NEW and existed and not bool(params.get("overwrite", false)):
|
|
464
|
+
return {"error": _err("exists", "File already exists (pass overwrite): %s" % to_path)}
|
|
465
|
+
var e := ResourceSaver.save(res, to_path, flags)
|
|
466
|
+
if e != OK:
|
|
467
|
+
return {"error": _err("save_failed", "ResourceSaver.save() returned %d" % e)}
|
|
468
|
+
return {"fields": {"replaced": true} if (existed and kind == SAVE_NEW) else {}}
|
|
469
|
+
|
|
470
|
+
|
|
376
471
|
# ------------------------------------------------------------- handlers ------
|
|
377
472
|
|
|
378
473
|
func _ping() -> Dictionary:
|
|
@@ -542,11 +637,11 @@ func _scene_new(params: Dictionary) -> Dictionary:
|
|
|
542
637
|
var e := packed.pack(root)
|
|
543
638
|
if e != OK:
|
|
544
639
|
return _err("pack_failed", "PackedScene.pack() returned %d" % e)
|
|
545
|
-
|
|
546
|
-
if
|
|
547
|
-
return
|
|
640
|
+
var saved := _commit_save(packed, path, params, SAVE_NEW)
|
|
641
|
+
if saved.has("error"):
|
|
642
|
+
return saved["error"]
|
|
548
643
|
EditorInterface.open_scene_from_path(path)
|
|
549
|
-
return _ok({"created": path, "root_type": root_type})
|
|
644
|
+
return _ok({"created": path, "root_type": root_type}.merged(saved["fields"]))
|
|
550
645
|
|
|
551
646
|
|
|
552
647
|
func _node_add(params: Dictionary) -> Dictionary:
|
|
@@ -561,14 +656,9 @@ func _node_add(params: Dictionary) -> Dictionary:
|
|
|
561
656
|
return _err("bad_type", "Cannot instantiate class: %s" % type)
|
|
562
657
|
var node: Node = ClassDB.instantiate(type)
|
|
563
658
|
node.name = String(params.get("name", type))
|
|
564
|
-
var
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
ur.add_do_method(node, "set_owner", root)
|
|
568
|
-
ur.add_do_reference(node)
|
|
569
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
570
|
-
ur.commit_action()
|
|
571
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": type})
|
|
659
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
660
|
+
added["type"] = type
|
|
661
|
+
return _ok(added)
|
|
572
662
|
|
|
573
663
|
|
|
574
664
|
func _node_delete(params: Dictionary) -> Dictionary:
|
|
@@ -1101,16 +1191,9 @@ func _node_duplicate(params: Dictionary) -> Dictionary:
|
|
|
1101
1191
|
var dup: Node = node.duplicate()
|
|
1102
1192
|
if params.has("name"):
|
|
1103
1193
|
dup.name = String(params.get("name"))
|
|
1104
|
-
var
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
ur.add_do_method(dup, "set_owner", root)
|
|
1108
|
-
for d in _descendants(dup):
|
|
1109
|
-
ur.add_do_method(d, "set_owner", root)
|
|
1110
|
-
ur.add_do_reference(dup)
|
|
1111
|
-
ur.add_undo_method(parent, "remove_child", dup)
|
|
1112
|
-
ur.commit_action()
|
|
1113
|
-
return _ok({"path": _path_of(root, dup), "name": String(dup.name), "type": dup.get_class()})
|
|
1194
|
+
var added := _commit_add(dup, parent, root, "Breakpoint: duplicate %s" % node.name, _descendants(dup))
|
|
1195
|
+
added["type"] = dup.get_class()
|
|
1196
|
+
return _ok(added)
|
|
1114
1197
|
|
|
1115
1198
|
|
|
1116
1199
|
func _node_get_children(params: Dictionary) -> Dictionary:
|
|
@@ -1221,14 +1304,10 @@ func _node_instantiate_scene(params: Dictionary) -> Dictionary:
|
|
|
1221
1304
|
return _err("instantiate_failed", "Could not instantiate %s" % scene_path)
|
|
1222
1305
|
if params.has("name"):
|
|
1223
1306
|
inst.name = String(params.get("name"))
|
|
1224
|
-
var
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
ur.add_do_reference(inst)
|
|
1229
|
-
ur.add_undo_method(parent, "remove_child", inst)
|
|
1230
|
-
ur.commit_action()
|
|
1231
|
-
return _ok({"path": _path_of(root, inst), "name": String(inst.name), "type": inst.get_class(), "scene": scene_path})
|
|
1307
|
+
var added := _commit_add(inst, parent, root, "Breakpoint: instance scene %s" % scene_path)
|
|
1308
|
+
added["type"] = inst.get_class()
|
|
1309
|
+
added["scene"] = scene_path
|
|
1310
|
+
return _ok(added)
|
|
1232
1311
|
|
|
1233
1312
|
|
|
1234
1313
|
func _node_move_child(params: Dictionary) -> Dictionary:
|
|
@@ -1569,11 +1648,11 @@ func _scene_pack(params: Dictionary) -> Dictionary:
|
|
|
1569
1648
|
if e != OK:
|
|
1570
1649
|
dup.free()
|
|
1571
1650
|
return _err("pack_failed", "PackedScene.pack() returned %d" % e)
|
|
1572
|
-
|
|
1651
|
+
var saved := _commit_save(packed, to_path, params, SAVE_NEW)
|
|
1573
1652
|
dup.free()
|
|
1574
|
-
if
|
|
1575
|
-
return
|
|
1576
|
-
return _ok({"packed": to_path, "branch": _path_of(root, branch)})
|
|
1653
|
+
if saved.has("error"):
|
|
1654
|
+
return saved["error"]
|
|
1655
|
+
return _ok({"packed": to_path, "branch": _path_of(root, branch)}.merged(saved["fields"]))
|
|
1577
1656
|
|
|
1578
1657
|
|
|
1579
1658
|
func _scene_save_as(params: Dictionary) -> Dictionary:
|
|
@@ -1779,10 +1858,10 @@ func _resource_create(params: Dictionary) -> Dictionary:
|
|
|
1779
1858
|
return _err("create_failed", "Could not instantiate %s" % cls)
|
|
1780
1859
|
for key in params.get("properties", {}):
|
|
1781
1860
|
res.set(String(key), Codec.decode(params["properties"][key]))
|
|
1782
|
-
var
|
|
1783
|
-
if
|
|
1784
|
-
return
|
|
1785
|
-
return _ok({"created": to_path, "type": cls})
|
|
1861
|
+
var saved := _commit_save(res, to_path, params, SAVE_NEW)
|
|
1862
|
+
if saved.has("error"):
|
|
1863
|
+
return saved["error"]
|
|
1864
|
+
return _ok({"created": to_path, "type": cls}.merged(saved["fields"]))
|
|
1786
1865
|
|
|
1787
1866
|
|
|
1788
1867
|
func _resource_load(params: Dictionary) -> Dictionary:
|
|
@@ -1813,10 +1892,15 @@ func _resource_save(params: Dictionary) -> Dictionary:
|
|
|
1813
1892
|
if res == null:
|
|
1814
1893
|
return _err("load_failed", "Could not load resource: %s" % from_path)
|
|
1815
1894
|
var flags := int(params.get("flags", 0))
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1895
|
+
# 🔵 THE KIND IS DERIVED HERE AND NOWHERE ELSE: `to_path` DEFAULTS to `from_path`,
|
|
1896
|
+
# so this one tool is a save-back when the caller named no destination and a
|
|
1897
|
+
# create when they did. Reading it off the arguments at the site is the honest
|
|
1898
|
+
# version; a constant would be wrong half the time.
|
|
1899
|
+
var kind := SAVE_BACK if to_path == from_path else SAVE_NEW
|
|
1900
|
+
var saved := _commit_save(res, to_path, params, kind, flags)
|
|
1901
|
+
if saved.has("error"):
|
|
1902
|
+
return saved["error"]
|
|
1903
|
+
return _ok({"saved": to_path, "from": from_path}.merged(saved["fields"]))
|
|
1820
1904
|
|
|
1821
1905
|
|
|
1822
1906
|
func _resource_duplicate(params: Dictionary) -> Dictionary:
|
|
@@ -1833,10 +1917,10 @@ func _resource_duplicate(params: Dictionary) -> Dictionary:
|
|
|
1833
1917
|
var dup := res.duplicate(deep)
|
|
1834
1918
|
if dup == null:
|
|
1835
1919
|
return _err("duplicate_failed", "Could not duplicate resource")
|
|
1836
|
-
var
|
|
1837
|
-
if
|
|
1838
|
-
return
|
|
1839
|
-
return _ok({"duplicated": to_path, "from": from_path, "deep": deep})
|
|
1920
|
+
var saved := _commit_save(dup, to_path, params, SAVE_NEW)
|
|
1921
|
+
if saved.has("error"):
|
|
1922
|
+
return saved["error"]
|
|
1923
|
+
return _ok({"duplicated": to_path, "from": from_path, "deep": deep}.merged(saved["fields"]))
|
|
1840
1924
|
|
|
1841
1925
|
|
|
1842
1926
|
func _resource_get_property(params: Dictionary) -> Dictionary:
|
|
@@ -1863,9 +1947,9 @@ func _resource_set_property(params: Dictionary) -> Dictionary:
|
|
|
1863
1947
|
if prop == "":
|
|
1864
1948
|
return _err("bad_params", "Missing 'property'")
|
|
1865
1949
|
res.set(prop, Codec.decode(params.get("value")))
|
|
1866
|
-
var
|
|
1867
|
-
if
|
|
1868
|
-
return
|
|
1950
|
+
var saved := _commit_save(res, path, params, SAVE_BACK)
|
|
1951
|
+
if saved.has("error"):
|
|
1952
|
+
return saved["error"]
|
|
1869
1953
|
return _ok({"path": path, "property": prop, "value": Codec.encode(res.get(prop))})
|
|
1870
1954
|
|
|
1871
1955
|
|
|
@@ -2102,10 +2186,11 @@ func _asset_gen_placeholder(params: Dictionary) -> Dictionary:
|
|
|
2102
2186
|
# pipeline) — the placeholder must be usable synchronously. External
|
|
2103
2187
|
# formats (a real backend's .png) go through asset.import instead.
|
|
2104
2188
|
var tex := ImageTexture.create_from_image(img)
|
|
2105
|
-
var
|
|
2106
|
-
if
|
|
2107
|
-
return
|
|
2189
|
+
var saved_e := _commit_save(tex, to_path, params, SAVE_NEW)
|
|
2190
|
+
if saved_e.has("error"):
|
|
2191
|
+
return saved_e["error"]
|
|
2108
2192
|
var desc := _import_and_describe(to_path)
|
|
2193
|
+
desc.merge(saved_e["fields"])
|
|
2109
2194
|
desc["kind"] = kind
|
|
2110
2195
|
desc["width"] = w
|
|
2111
2196
|
desc["height"] = h
|
|
@@ -2114,10 +2199,11 @@ func _asset_gen_placeholder(params: Dictionary) -> Dictionary:
|
|
|
2114
2199
|
"audio_sfx":
|
|
2115
2200
|
var dur := clampi(int(params.get("duration_ms", 300)), 20, 5000)
|
|
2116
2201
|
var stream := _gen_audio(seed_hash, dur)
|
|
2117
|
-
var
|
|
2118
|
-
if
|
|
2119
|
-
return
|
|
2202
|
+
var saved_e2 := _commit_save(stream, to_path, params, SAVE_NEW)
|
|
2203
|
+
if saved_e2.has("error"):
|
|
2204
|
+
return saved_e2["error"]
|
|
2120
2205
|
var desc2 := _import_and_describe(to_path)
|
|
2206
|
+
desc2.merge(saved_e2["fields"])
|
|
2121
2207
|
desc2["kind"] = kind
|
|
2122
2208
|
desc2["duration_ms"] = dur
|
|
2123
2209
|
desc2["format"] = "AudioStreamWAV"
|
|
@@ -2125,10 +2211,11 @@ func _asset_gen_placeholder(params: Dictionary) -> Dictionary:
|
|
|
2125
2211
|
"model":
|
|
2126
2212
|
var shape := String(params.get("shape", "box"))
|
|
2127
2213
|
var mesh := _gen_mesh(shape, seed_hash)
|
|
2128
|
-
var
|
|
2129
|
-
if
|
|
2130
|
-
return
|
|
2214
|
+
var saved_e3 := _commit_save(mesh, to_path, params, SAVE_NEW)
|
|
2215
|
+
if saved_e3.has("error"):
|
|
2216
|
+
return saved_e3["error"]
|
|
2131
2217
|
var desc3 := _import_and_describe(to_path)
|
|
2218
|
+
desc3.merge(saved_e3["fields"])
|
|
2132
2219
|
desc3["kind"] = kind
|
|
2133
2220
|
desc3["shape"] = shape
|
|
2134
2221
|
desc3["format"] = mesh.get_class()
|
|
@@ -2282,14 +2369,9 @@ func _anim_player_create(params: Dictionary) -> Dictionary:
|
|
|
2282
2369
|
var node := AnimationPlayer.new()
|
|
2283
2370
|
node.name = String(params.get("name", "AnimationPlayer"))
|
|
2284
2371
|
node.add_animation_library("", AnimationLibrary.new())
|
|
2285
|
-
var
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
ur.add_do_method(node, "set_owner", root)
|
|
2289
|
-
ur.add_do_reference(node)
|
|
2290
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
2291
|
-
ur.commit_action()
|
|
2292
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": "AnimationPlayer"})
|
|
2372
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add AnimationPlayer %s" % node.name)
|
|
2373
|
+
added["type"] = "AnimationPlayer"
|
|
2374
|
+
return _ok(added)
|
|
2293
2375
|
|
|
2294
2376
|
|
|
2295
2377
|
func _anim_create(params: Dictionary) -> Dictionary:
|
|
@@ -2607,14 +2689,12 @@ func _anim_tree_create(params: Dictionary) -> Dictionary:
|
|
|
2607
2689
|
if anim_player_path != "":
|
|
2608
2690
|
node.set("anim_player", NodePath(anim_player_path))
|
|
2609
2691
|
node.set("active", bool(params.get("active", false)))
|
|
2610
|
-
var
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
ur.commit_action()
|
|
2617
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": "AnimationTree", "root_type": rt, "anim_player": anim_player_path, "active": bool(node.get("active"))})
|
|
2692
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add AnimationTree %s" % node.name)
|
|
2693
|
+
added["type"] = "AnimationTree"
|
|
2694
|
+
added["root_type"] = rt
|
|
2695
|
+
added["anim_player"] = anim_player_path
|
|
2696
|
+
added["active"] = bool(node.get("active"))
|
|
2697
|
+
return _ok(added)
|
|
2618
2698
|
|
|
2619
2699
|
|
|
2620
2700
|
func _anim_tree_add_node(params: Dictionary) -> Dictionary:
|
|
@@ -2760,11 +2840,11 @@ func _tileset_create(params: Dictionary) -> Dictionary:
|
|
|
2760
2840
|
var ts := TileSet.new()
|
|
2761
2841
|
if params.has("tile_size"):
|
|
2762
2842
|
ts.set("tile_size", _to_vec2i(params.get("tile_size")))
|
|
2763
|
-
var
|
|
2764
|
-
if
|
|
2765
|
-
return
|
|
2843
|
+
var saved := _commit_save(ts, to_path, params, SAVE_NEW)
|
|
2844
|
+
if saved.has("error"):
|
|
2845
|
+
return saved["error"]
|
|
2766
2846
|
var tsz: Vector2i = ts.get("tile_size")
|
|
2767
|
-
return _ok({"created": to_path, "tile_size": [tsz.x, tsz.y]})
|
|
2847
|
+
return _ok({"created": to_path, "tile_size": [tsz.x, tsz.y]}.merged(saved["fields"]))
|
|
2768
2848
|
|
|
2769
2849
|
|
|
2770
2850
|
func _tileset_add_source(params: Dictionary) -> Dictionary:
|
|
@@ -2789,9 +2869,9 @@ func _tileset_add_source(params: Dictionary) -> Dictionary:
|
|
|
2789
2869
|
if params.has("separation"):
|
|
2790
2870
|
atlas.set("separation", _to_vec2i(params.get("separation")))
|
|
2791
2871
|
var assigned: int = ts.add_source(atlas, int(params.get("source_id", -1)))
|
|
2792
|
-
var
|
|
2793
|
-
if
|
|
2794
|
-
return
|
|
2872
|
+
var saved := _commit_save(ts, tileset_path, params, SAVE_BACK)
|
|
2873
|
+
if saved.has("error"):
|
|
2874
|
+
return saved["error"]
|
|
2795
2875
|
return _ok({"tileset": tileset_path, "source_id": assigned, "texture": texture_path, "texture_region_size": [region.x, region.y], "source_count": ts.get_source_count()})
|
|
2796
2876
|
|
|
2797
2877
|
|
|
@@ -2813,9 +2893,9 @@ func _tileset_add_tile(params: Dictionary) -> Dictionary:
|
|
|
2813
2893
|
if params.has("size"):
|
|
2814
2894
|
size = _to_vec2i(params.get("size"))
|
|
2815
2895
|
src.create_tile(coords, size)
|
|
2816
|
-
var
|
|
2817
|
-
if
|
|
2818
|
-
return
|
|
2896
|
+
var saved := _commit_save(ts, tileset_path, params, SAVE_BACK)
|
|
2897
|
+
if saved.has("error"):
|
|
2898
|
+
return saved["error"]
|
|
2819
2899
|
return _ok({"tileset": tileset_path, "source_id": sid, "atlas_coords": [coords.x, coords.y], "size": [size.x, size.y], "tiles_count": src.get_tiles_count()})
|
|
2820
2900
|
|
|
2821
2901
|
|
|
@@ -2850,9 +2930,9 @@ func _tileset_set_tile_collision(params: Dictionary) -> Dictionary:
|
|
|
2850
2930
|
var one_way := bool(params.get("one_way", false))
|
|
2851
2931
|
if params.has("one_way"):
|
|
2852
2932
|
td.set_collision_polygon_one_way(layer, poly_index, one_way)
|
|
2853
|
-
var
|
|
2854
|
-
if
|
|
2855
|
-
return
|
|
2933
|
+
var saved := _commit_save(ts, tileset_path, params, SAVE_BACK)
|
|
2934
|
+
if saved.has("error"):
|
|
2935
|
+
return saved["error"]
|
|
2856
2936
|
return _ok({"tileset": tileset_path, "source_id": sid, "atlas_coords": [coords.x, coords.y], "physics_layer": layer, "polygon_index": poly_index, "points": poly.size(), "one_way": one_way})
|
|
2857
2937
|
|
|
2858
2938
|
|
|
@@ -2886,14 +2966,10 @@ func _tilemaplayer_create(params: Dictionary) -> Dictionary:
|
|
|
2886
2966
|
if ts == null:
|
|
2887
2967
|
return _err("not_found", "TileSet not found: %s" % tileset_path)
|
|
2888
2968
|
layer.tile_set = ts
|
|
2889
|
-
var
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
ur.add_do_reference(layer)
|
|
2894
|
-
ur.add_undo_method(parent, "remove_child", layer)
|
|
2895
|
-
ur.commit_action()
|
|
2896
|
-
return _ok({"path": _path_of(root, layer), "name": String(layer.name), "type": "TileMapLayer", "tile_set": tileset_path})
|
|
2969
|
+
var added := _commit_add(layer, parent, root, "Breakpoint: add TileMapLayer %s" % layer.name)
|
|
2970
|
+
added["type"] = "TileMapLayer"
|
|
2971
|
+
added["tile_set"] = tileset_path
|
|
2972
|
+
return _ok(added)
|
|
2897
2973
|
|
|
2898
2974
|
|
|
2899
2975
|
func _tilemap_set_cell(params: Dictionary) -> Dictionary:
|
|
@@ -3041,14 +3117,11 @@ func _body_create(params: Dictionary) -> Dictionary:
|
|
|
3041
3117
|
return _err("bad_type", "Cannot instantiate class: %s" % cls)
|
|
3042
3118
|
var node: Node = ClassDB.instantiate(cls)
|
|
3043
3119
|
node.name = String(params.get("name", cls))
|
|
3044
|
-
var
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
3050
|
-
ur.commit_action()
|
|
3051
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": cls, "body": kind, "dim": ("3d" if dim3 else "2d")})
|
|
3120
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3121
|
+
added["type"] = cls
|
|
3122
|
+
added["body"] = kind
|
|
3123
|
+
added["dim"] = ("3d" if dim3 else "2d")
|
|
3124
|
+
return _ok(added)
|
|
3052
3125
|
|
|
3053
3126
|
|
|
3054
3127
|
func _make_collision_shape(kind: String, dim3: bool, params: Dictionary):
|
|
@@ -3118,14 +3191,12 @@ func _collisionshape_add(params: Dictionary) -> Dictionary:
|
|
|
3118
3191
|
cs2.set("shape", shape_res)
|
|
3119
3192
|
node = cs2
|
|
3120
3193
|
node.name = String(params.get("name", node.get_class()))
|
|
3121
|
-
var
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
ur.commit_action()
|
|
3128
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": node.get_class(), "shape": kind, "shape_class": shape_res.get_class(), "dim": ("3d" if dim3 else "2d")})
|
|
3194
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3195
|
+
added["type"] = node.get_class()
|
|
3196
|
+
added["shape"] = kind
|
|
3197
|
+
added["shape_class"] = shape_res.get_class()
|
|
3198
|
+
added["dim"] = ("3d" if dim3 else "2d")
|
|
3199
|
+
return _ok(added)
|
|
3129
3200
|
|
|
3130
3201
|
|
|
3131
3202
|
func _body_set_collision_layer(params: Dictionary) -> Dictionary:
|
|
@@ -3282,14 +3353,13 @@ func _joint_create(params: Dictionary) -> Dictionary:
|
|
|
3282
3353
|
node.set("node_a", NodePath(String(params.get("node_a"))))
|
|
3283
3354
|
if params.has("node_b"):
|
|
3284
3355
|
node.set("node_b", NodePath(String(params.get("node_b"))))
|
|
3285
|
-
var
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": cls, "joint": kind, "dim": ("3d" if dim3 else "2d"), "node_a": String(node.get("node_a")), "node_b": String(node.get("node_b"))})
|
|
3356
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3357
|
+
added["type"] = cls
|
|
3358
|
+
added["joint"] = kind
|
|
3359
|
+
added["dim"] = ("3d" if dim3 else "2d")
|
|
3360
|
+
added["node_a"] = String(node.get("node_a"))
|
|
3361
|
+
added["node_b"] = String(node.get("node_b"))
|
|
3362
|
+
return _ok(added)
|
|
3293
3363
|
|
|
3294
3364
|
|
|
3295
3365
|
func _joint_set_bodies(params: Dictionary) -> Dictionary:
|
|
@@ -3341,14 +3411,11 @@ func _collisionpolygon_add(params: Dictionary) -> Dictionary:
|
|
|
3341
3411
|
c2.set("build_mode", bm)
|
|
3342
3412
|
node = c2
|
|
3343
3413
|
node.name = String(params.get("name", node.get_class()))
|
|
3344
|
-
var
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
3350
|
-
ur.commit_action()
|
|
3351
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": node.get_class(), "dim": ("3d" if dim3 else "2d"), "points": pts.size()})
|
|
3414
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3415
|
+
added["type"] = node.get_class()
|
|
3416
|
+
added["dim"] = ("3d" if dim3 else "2d")
|
|
3417
|
+
added["points"] = pts.size()
|
|
3418
|
+
return _ok(added)
|
|
3352
3419
|
|
|
3353
3420
|
|
|
3354
3421
|
func _rigidbody_set_properties(params: Dictionary) -> Dictionary:
|
|
@@ -3461,14 +3528,13 @@ func _particles_create(params: Dictionary) -> Dictionary:
|
|
|
3461
3528
|
node.set("lifetime", float(params.get("lifetime")))
|
|
3462
3529
|
if params.has("emitting"):
|
|
3463
3530
|
node.set("emitting", bool(params.get("emitting")))
|
|
3464
|
-
var
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": node.get_class(), "dim": ("3d" if dim3 else "2d"), "amount": int(node.get("amount")), "lifetime": float(node.get("lifetime")), "emitting": bool(node.get("emitting"))})
|
|
3531
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3532
|
+
added["type"] = node.get_class()
|
|
3533
|
+
added["dim"] = ("3d" if dim3 else "2d")
|
|
3534
|
+
added["amount"] = int(node.get("amount"))
|
|
3535
|
+
added["lifetime"] = float(node.get("lifetime"))
|
|
3536
|
+
added["emitting"] = bool(node.get("emitting"))
|
|
3537
|
+
return _ok(added)
|
|
3472
3538
|
|
|
3473
3539
|
|
|
3474
3540
|
func _particles_set_process_material(params: Dictionary) -> Dictionary:
|
|
@@ -3621,10 +3687,10 @@ func _shader_create(params: Dictionary) -> Dictionary:
|
|
|
3621
3687
|
var sh := Shader.new()
|
|
3622
3688
|
if params.has("code"):
|
|
3623
3689
|
sh.code = String(params.get("code"))
|
|
3624
|
-
var
|
|
3625
|
-
if
|
|
3626
|
-
return
|
|
3627
|
-
return _ok({"created": to_path, "type": "Shader", "code_length": sh.code.length()})
|
|
3690
|
+
var saved := _commit_save(sh, to_path, params, SAVE_NEW)
|
|
3691
|
+
if saved.has("error"):
|
|
3692
|
+
return saved["error"]
|
|
3693
|
+
return _ok({"created": to_path, "type": "Shader", "code_length": sh.code.length()}.merged(saved["fields"]))
|
|
3628
3694
|
|
|
3629
3695
|
|
|
3630
3696
|
func _shader_set_code(params: Dictionary) -> Dictionary:
|
|
@@ -3638,9 +3704,9 @@ func _shader_set_code(params: Dictionary) -> Dictionary:
|
|
|
3638
3704
|
return _err("bad_type", "%s is not a Shader" % path)
|
|
3639
3705
|
var sh := res as Shader
|
|
3640
3706
|
sh.code = String(params.get("code"))
|
|
3641
|
-
var
|
|
3642
|
-
if
|
|
3643
|
-
return
|
|
3707
|
+
var saved := _commit_save(sh, path, params, SAVE_BACK)
|
|
3708
|
+
if saved.has("error"):
|
|
3709
|
+
return saved["error"]
|
|
3644
3710
|
return _ok({"path": path, "code_length": sh.code.length()})
|
|
3645
3711
|
|
|
3646
3712
|
|
|
@@ -3769,14 +3835,14 @@ func _audio_player_create(params: Dictionary) -> Dictionary:
|
|
|
3769
3835
|
if not (sres is AudioStream):
|
|
3770
3836
|
return _err("bad_type", "%s is not an AudioStream" % stream_path)
|
|
3771
3837
|
node.set("stream", sres as AudioStream)
|
|
3772
|
-
var
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
return _ok(
|
|
3838
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3839
|
+
added["type"] = node.get_class()
|
|
3840
|
+
added["dim"] = dim
|
|
3841
|
+
added["autoplay"] = bool(node.get("autoplay"))
|
|
3842
|
+
added["volume_db"] = float(node.get("volume_db"))
|
|
3843
|
+
added["bus"] = String(node.get("bus"))
|
|
3844
|
+
added["stream_path"] = stream_path
|
|
3845
|
+
return _ok(added)
|
|
3780
3846
|
|
|
3781
3847
|
|
|
3782
3848
|
func _audio_set_stream(params: Dictionary) -> Dictionary:
|
|
@@ -3847,10 +3913,10 @@ func _audio_set_bus_layout(params: Dictionary) -> Dictionary:
|
|
|
3847
3913
|
if not to_path.begins_with("res://"):
|
|
3848
3914
|
return _err("bad_params", "'to_path' must be a res:// path")
|
|
3849
3915
|
var layout = AudioServer.generate_bus_layout()
|
|
3850
|
-
var
|
|
3851
|
-
if
|
|
3852
|
-
return
|
|
3853
|
-
return _ok({"saved": to_path, "bus_count": AudioServer.get_bus_count()})
|
|
3916
|
+
var saved := _commit_save(layout, to_path, params, SAVE_NEW)
|
|
3917
|
+
if saved.has("error"):
|
|
3918
|
+
return saved["error"]
|
|
3919
|
+
return _ok({"saved": to_path, "bus_count": AudioServer.get_bus_count()}.merged(saved["fields"]))
|
|
3854
3920
|
|
|
3855
3921
|
|
|
3856
3922
|
# ---------------------------------------------------------------- Group G: UI / control / theming ----
|
|
@@ -3876,14 +3942,9 @@ func _control_create(params: Dictionary) -> Dictionary:
|
|
|
3876
3942
|
node.name = String(params.get("name", type))
|
|
3877
3943
|
if params.has("text") and _has_property(node, "text"):
|
|
3878
3944
|
node.set("text", String(params.get("text")))
|
|
3879
|
-
var
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
ur.add_do_method(node, "set_owner", root)
|
|
3883
|
-
ur.add_do_reference(node)
|
|
3884
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
3885
|
-
ur.commit_action()
|
|
3886
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": type})
|
|
3945
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
3946
|
+
added["type"] = type
|
|
3947
|
+
return _ok(added)
|
|
3887
3948
|
|
|
3888
3949
|
|
|
3889
3950
|
func _container_add_child(params: Dictionary) -> Dictionary:
|
|
@@ -3902,14 +3963,10 @@ func _container_add_child(params: Dictionary) -> Dictionary:
|
|
|
3902
3963
|
return _err("bad_type", "%s is not a Control subclass" % type)
|
|
3903
3964
|
var node: Node = ClassDB.instantiate(type)
|
|
3904
3965
|
node.name = String(params.get("name", type))
|
|
3905
|
-
var
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
ur.add_do_reference(node)
|
|
3910
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
3911
|
-
ur.commit_action()
|
|
3912
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": type, "container": _path_of(root, parent)})
|
|
3966
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s to container" % node.name)
|
|
3967
|
+
added["type"] = type
|
|
3968
|
+
added["container"] = _path_of(root, parent)
|
|
3969
|
+
return _ok(added)
|
|
3913
3970
|
|
|
3914
3971
|
|
|
3915
3972
|
func _control_set_anchors(params: Dictionary) -> Dictionary:
|
|
@@ -4043,10 +4100,10 @@ func _theme_create(params: Dictionary) -> Dictionary:
|
|
|
4043
4100
|
if not to_path.begins_with("res://"):
|
|
4044
4101
|
return _err("bad_params", "'to_path' must be a res:// path")
|
|
4045
4102
|
var theme := Theme.new()
|
|
4046
|
-
var
|
|
4047
|
-
if
|
|
4048
|
-
return
|
|
4049
|
-
return _ok({"created": to_path, "type": "Theme"})
|
|
4103
|
+
var saved := _commit_save(theme, to_path, params, SAVE_NEW)
|
|
4104
|
+
if saved.has("error"):
|
|
4105
|
+
return saved["error"]
|
|
4106
|
+
return _ok({"created": to_path, "type": "Theme"}.merged(saved["fields"]))
|
|
4050
4107
|
|
|
4051
4108
|
|
|
4052
4109
|
func _theme_set_color(params: Dictionary) -> Dictionary:
|
|
@@ -4060,9 +4117,9 @@ func _theme_set_color(params: Dictionary) -> Dictionary:
|
|
|
4060
4117
|
return _err("bad_params", "Missing 'name' or 'theme_type'")
|
|
4061
4118
|
var col := _to_color(params.get("color"))
|
|
4062
4119
|
theme.set_color(iname, ttype, col)
|
|
4063
|
-
var
|
|
4064
|
-
if
|
|
4065
|
-
return
|
|
4120
|
+
var saved := _commit_save(theme, path, params, SAVE_BACK)
|
|
4121
|
+
if saved.has("error"):
|
|
4122
|
+
return saved["error"]
|
|
4066
4123
|
return _ok({"path": path, "name": iname, "theme_type": ttype, "color": [col.r, col.g, col.b, col.a]})
|
|
4067
4124
|
|
|
4068
4125
|
|
|
@@ -4082,9 +4139,9 @@ func _theme_set_font(params: Dictionary) -> Dictionary:
|
|
|
4082
4139
|
if not (fres is Font):
|
|
4083
4140
|
return _err("bad_type", "%s is not a Font" % font_path)
|
|
4084
4141
|
theme.set_font(iname, ttype, fres as Font)
|
|
4085
|
-
var
|
|
4086
|
-
if
|
|
4087
|
-
return
|
|
4142
|
+
var saved := _commit_save(theme, path, params, SAVE_BACK)
|
|
4143
|
+
if saved.has("error"):
|
|
4144
|
+
return saved["error"]
|
|
4088
4145
|
return _ok({"path": path, "name": iname, "theme_type": ttype, "font_path": font_path})
|
|
4089
4146
|
|
|
4090
4147
|
|
|
@@ -4104,9 +4161,9 @@ func _theme_set_stylebox(params: Dictionary) -> Dictionary:
|
|
|
4104
4161
|
if not (sres is StyleBox):
|
|
4105
4162
|
return _err("bad_type", "%s is not a StyleBox" % sb_path)
|
|
4106
4163
|
theme.set_stylebox(iname, ttype, sres as StyleBox)
|
|
4107
|
-
var
|
|
4108
|
-
if
|
|
4109
|
-
return
|
|
4164
|
+
var saved := _commit_save(theme, path, params, SAVE_BACK)
|
|
4165
|
+
if saved.has("error"):
|
|
4166
|
+
return saved["error"]
|
|
4110
4167
|
return _ok({"path": path, "name": iname, "theme_type": ttype, "stylebox_path": sb_path})
|
|
4111
4168
|
|
|
4112
4169
|
|
|
@@ -4123,9 +4180,9 @@ func _theme_set_constant(params: Dictionary) -> Dictionary:
|
|
|
4123
4180
|
return _err("bad_params", "Missing 'value'")
|
|
4124
4181
|
var val := int(params.get("value"))
|
|
4125
4182
|
theme.set_constant(iname, ttype, val)
|
|
4126
|
-
var
|
|
4127
|
-
if
|
|
4128
|
-
return
|
|
4183
|
+
var saved := _commit_save(theme, path, params, SAVE_BACK)
|
|
4184
|
+
if saved.has("error"):
|
|
4185
|
+
return saved["error"]
|
|
4129
4186
|
return _ok({"path": path, "name": iname, "theme_type": ttype, "value": val})
|
|
4130
4187
|
|
|
4131
4188
|
|
|
@@ -4216,14 +4273,10 @@ func _meshinstance_create(params: Dictionary) -> Dictionary:
|
|
|
4216
4273
|
node.name = String(params.get("name", "MeshInstance3D"))
|
|
4217
4274
|
if mesh_res != null:
|
|
4218
4275
|
node.mesh = mesh_res
|
|
4219
|
-
var
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
ur.add_do_reference(node)
|
|
4224
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
4225
|
-
ur.commit_action()
|
|
4226
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": "MeshInstance3D", "mesh_path": mesh_path})
|
|
4276
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
4277
|
+
added["type"] = "MeshInstance3D"
|
|
4278
|
+
added["mesh_path"] = mesh_path
|
|
4279
|
+
return _ok(added)
|
|
4227
4280
|
|
|
4228
4281
|
|
|
4229
4282
|
func _mesh_set_surface_material(params: Dictionary) -> Dictionary:
|
|
@@ -4277,10 +4330,10 @@ func _primitive_mesh_create(params: Dictionary) -> Dictionary:
|
|
|
4277
4330
|
var mesh: Mesh = ClassDB.instantiate(cls)
|
|
4278
4331
|
if mesh == null:
|
|
4279
4332
|
return _err("create_failed", "Could not instantiate %s" % cls)
|
|
4280
|
-
var
|
|
4281
|
-
if
|
|
4282
|
-
return
|
|
4283
|
-
return _ok({"created": to_path, "type": cls, "shape": shape})
|
|
4333
|
+
var saved := _commit_save(mesh, to_path, params, SAVE_NEW)
|
|
4334
|
+
if saved.has("error"):
|
|
4335
|
+
return saved["error"]
|
|
4336
|
+
return _ok({"created": to_path, "type": cls, "shape": shape}.merged(saved["fields"]))
|
|
4284
4337
|
|
|
4285
4338
|
|
|
4286
4339
|
func _light_create(params: Dictionary) -> Dictionary:
|
|
@@ -4297,14 +4350,10 @@ func _light_create(params: Dictionary) -> Dictionary:
|
|
|
4297
4350
|
var cls := String(classes[kind])
|
|
4298
4351
|
var node: Node = ClassDB.instantiate(cls)
|
|
4299
4352
|
node.name = String(params.get("name", cls))
|
|
4300
|
-
var
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
ur.add_do_reference(node)
|
|
4305
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
4306
|
-
ur.commit_action()
|
|
4307
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": cls, "kind": kind})
|
|
4353
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
4354
|
+
added["type"] = cls
|
|
4355
|
+
added["kind"] = kind
|
|
4356
|
+
return _ok(added)
|
|
4308
4357
|
|
|
4309
4358
|
|
|
4310
4359
|
func _camera_create(params: Dictionary) -> Dictionary:
|
|
@@ -4318,14 +4367,10 @@ func _camera_create(params: Dictionary) -> Dictionary:
|
|
|
4318
4367
|
node.name = String(params.get("name", "Camera3D"))
|
|
4319
4368
|
if bool(params.get("current", false)):
|
|
4320
4369
|
node.current = true
|
|
4321
|
-
var
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
ur.add_do_reference(node)
|
|
4326
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
4327
|
-
ur.commit_action()
|
|
4328
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": "Camera3D", "current": node.current})
|
|
4370
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
4371
|
+
added["type"] = "Camera3D"
|
|
4372
|
+
added["current"] = node.current
|
|
4373
|
+
return _ok(added)
|
|
4329
4374
|
|
|
4330
4375
|
|
|
4331
4376
|
func _environment_create(params: Dictionary) -> Dictionary:
|
|
@@ -4340,10 +4385,10 @@ func _environment_create(params: Dictionary) -> Dictionary:
|
|
|
4340
4385
|
env.background_mode = int(modes[bg])
|
|
4341
4386
|
if params.has("ambient_color"):
|
|
4342
4387
|
env.ambient_light_color = _to_color(params.get("ambient_color"))
|
|
4343
|
-
var
|
|
4344
|
-
if
|
|
4345
|
-
return
|
|
4346
|
-
return _ok({"created": to_path, "type": "Environment", "background_mode": bg})
|
|
4388
|
+
var saved := _commit_save(env, to_path, params, SAVE_NEW)
|
|
4389
|
+
if saved.has("error"):
|
|
4390
|
+
return saved["error"]
|
|
4391
|
+
return _ok({"created": to_path, "type": "Environment", "background_mode": bg}.merged(saved["fields"]))
|
|
4347
4392
|
|
|
4348
4393
|
|
|
4349
4394
|
func _environment_set_sky(params: Dictionary) -> Dictionary:
|
|
@@ -4367,9 +4412,9 @@ func _environment_set_sky(params: Dictionary) -> Dictionary:
|
|
|
4367
4412
|
return _err("bad_params", "Unknown sky_material: %s (procedural/physical/panorama)" % mat_kind)
|
|
4368
4413
|
env.sky = sky
|
|
4369
4414
|
env.background_mode = Environment.BG_SKY
|
|
4370
|
-
var
|
|
4371
|
-
if
|
|
4372
|
-
return
|
|
4415
|
+
var saved := _commit_save(env, path, params, SAVE_BACK)
|
|
4416
|
+
if saved.has("error"):
|
|
4417
|
+
return saved["error"]
|
|
4373
4418
|
return _ok({"path": path, "background_mode": "sky", "sky_material": mat_kind})
|
|
4374
4419
|
|
|
4375
4420
|
|
|
@@ -4389,14 +4434,10 @@ func _csg_create(params: Dictionary) -> Dictionary:
|
|
|
4389
4434
|
return _err("bad_type", "Cannot instantiate class: %s" % cls)
|
|
4390
4435
|
var node: Node = ClassDB.instantiate(cls)
|
|
4391
4436
|
node.name = String(params.get("name", cls))
|
|
4392
|
-
var
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
ur.add_do_reference(node)
|
|
4397
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
4398
|
-
ur.commit_action()
|
|
4399
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": cls, "shape": shape})
|
|
4437
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
4438
|
+
added["type"] = cls
|
|
4439
|
+
added["shape"] = shape
|
|
4440
|
+
return _ok(added)
|
|
4400
4441
|
|
|
4401
4442
|
|
|
4402
4443
|
func _navregion_create(params: Dictionary) -> Dictionary:
|
|
@@ -4410,14 +4451,10 @@ func _navregion_create(params: Dictionary) -> Dictionary:
|
|
|
4410
4451
|
node.name = String(params.get("name", "NavigationRegion3D"))
|
|
4411
4452
|
if bool(params.get("with_navmesh", true)):
|
|
4412
4453
|
node.navigation_mesh = NavigationMesh.new()
|
|
4413
|
-
var
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
ur.add_do_reference(node)
|
|
4418
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
4419
|
-
ur.commit_action()
|
|
4420
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": "NavigationRegion3D", "has_navmesh": node.navigation_mesh != null})
|
|
4454
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
4455
|
+
added["type"] = "NavigationRegion3D"
|
|
4456
|
+
added["has_navmesh"] = node.navigation_mesh != null
|
|
4457
|
+
return _ok(added)
|
|
4421
4458
|
|
|
4422
4459
|
|
|
4423
4460
|
func _navagent_configure(params: Dictionary) -> Dictionary:
|
|
@@ -4441,14 +4478,10 @@ func _navagent_configure(params: Dictionary) -> Dictionary:
|
|
|
4441
4478
|
node.target_desired_distance = float(params.get("target_desired_distance"))
|
|
4442
4479
|
if params.has("avoidance_enabled"):
|
|
4443
4480
|
node.avoidance_enabled = bool(params.get("avoidance_enabled"))
|
|
4444
|
-
var
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
ur.add_do_reference(node)
|
|
4449
|
-
ur.add_undo_method(parent, "remove_child", node)
|
|
4450
|
-
ur.commit_action()
|
|
4451
|
-
return _ok({"path": _path_of(root, node), "name": String(node.name), "type": "NavigationAgent3D", "config": {"radius": node.radius, "height": node.height, "max_speed": node.max_speed, "path_desired_distance": node.path_desired_distance, "target_desired_distance": node.target_desired_distance, "avoidance_enabled": node.avoidance_enabled}})
|
|
4481
|
+
var added := _commit_add(node, parent, root, "Breakpoint: add %s" % node.name)
|
|
4482
|
+
added["type"] = "NavigationAgent3D"
|
|
4483
|
+
added["config"] = {"radius": node.radius, "height": node.height, "max_speed": node.max_speed, "path_desired_distance": node.path_desired_distance, "target_desired_distance": node.target_desired_distance, "avoidance_enabled": node.avoidance_enabled}
|
|
4484
|
+
return _ok(added)
|
|
4452
4485
|
|
|
4453
4486
|
|
|
4454
4487
|
# ------------------------------------------------ Group I: input/config/testing ----
|
|
@@ -4757,20 +4790,11 @@ func _mp_add_spawner(params: Dictionary) -> Dictionary:
|
|
|
4757
4790
|
if sp.begins_with("res://"):
|
|
4758
4791
|
spawner.add_spawnable_scene(sp)
|
|
4759
4792
|
added_scenes.append(sp)
|
|
4760
|
-
var
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
ur.add_undo_method(parent, "remove_child", spawner)
|
|
4766
|
-
ur.commit_action()
|
|
4767
|
-
return _ok({
|
|
4768
|
-
"path": _path_of(root, spawner),
|
|
4769
|
-
"name": String(spawner.name),
|
|
4770
|
-
"type": "MultiplayerSpawner",
|
|
4771
|
-
"spawn_path": String(spawner.spawn_path),
|
|
4772
|
-
"spawnable_scenes": added_scenes,
|
|
4773
|
-
})
|
|
4793
|
+
var added := _commit_add(spawner, parent, root, "Breakpoint: add %s" % spawner.name)
|
|
4794
|
+
added["type"] = "MultiplayerSpawner"
|
|
4795
|
+
added["spawn_path"] = String(spawner.spawn_path)
|
|
4796
|
+
added["spawnable_scenes"] = added_scenes
|
|
4797
|
+
return _ok(added)
|
|
4774
4798
|
|
|
4775
4799
|
|
|
4776
4800
|
func _mp_add_synchronizer(params: Dictionary) -> Dictionary:
|
|
@@ -4801,20 +4825,11 @@ func _mp_add_synchronizer(params: Dictionary) -> Dictionary:
|
|
|
4801
4825
|
cfg.property_set_replication_mode(np, mode)
|
|
4802
4826
|
added_props.append(String(p))
|
|
4803
4827
|
sync.replication_config = cfg
|
|
4804
|
-
var
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
ur.add_undo_method(parent, "remove_child", sync)
|
|
4810
|
-
ur.commit_action()
|
|
4811
|
-
return _ok({
|
|
4812
|
-
"path": _path_of(root, sync),
|
|
4813
|
-
"name": String(sync.name),
|
|
4814
|
-
"type": "MultiplayerSynchronizer",
|
|
4815
|
-
"root_path": String(sync.root_path),
|
|
4816
|
-
"properties": added_props,
|
|
4817
|
-
})
|
|
4828
|
+
var added := _commit_add(sync, parent, root, "Breakpoint: add %s" % sync.name)
|
|
4829
|
+
added["type"] = "MultiplayerSynchronizer"
|
|
4830
|
+
added["root_path"] = String(sync.root_path)
|
|
4831
|
+
added["properties"] = added_props
|
|
4832
|
+
return _ok(added)
|
|
4818
4833
|
|
|
4819
4834
|
|
|
4820
4835
|
func _mp_set_authority(params: Dictionary) -> Dictionary:
|
|
@@ -4862,7 +4877,15 @@ func _mp_write_script(params: Dictionary) -> Dictionary:
|
|
|
4862
4877
|
var efs := EditorInterface.get_resource_filesystem()
|
|
4863
4878
|
efs.update_file(to_path)
|
|
4864
4879
|
efs.scan()
|
|
4865
|
-
|
|
4880
|
+
# 🆕 284 — `replaced` JOINS `created`, IT DOES NOT REPLACE IT. This reply has carried
|
|
4881
|
+
# `created: false` since the scaffold family was built, which is a fifth spelling of
|
|
4882
|
+
# the one question 284 unified — and callers branch on it, so it stays. What is added
|
|
4883
|
+
# is the field every other destination-writing tool now answers with, present only
|
|
4884
|
+
# when it happened, so one convention covers the whole surface.
|
|
4885
|
+
var out := {"status": "written", "path": to_path, "bytes": content.to_utf8_buffer().size(), "created": not existed}
|
|
4886
|
+
if existed:
|
|
4887
|
+
out["replaced"] = true
|
|
4888
|
+
return _ok(out)
|
|
4866
4889
|
|
|
4867
4890
|
|
|
4868
4891
|
## Detect which known game-backend SDKs are installed in this project. Each is
|