breakpoint-mcp 1.0.0 → 1.1.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/dist/config.js +6 -30
- package/dist/index.js +3 -3
- package/dist/tools/editor/animation.js +162 -0
- package/dist/tools/editor/audio.js +109 -0
- package/dist/tools/editor/common.js +31 -0
- package/dist/tools/editor/core.js +49 -0
- package/dist/tools/editor/filesystem.js +35 -0
- package/dist/tools/editor/introspection.js +73 -0
- package/dist/tools/editor/node.js +171 -0
- package/dist/tools/editor/particles.js +96 -0
- package/dist/tools/editor/physics.js +236 -0
- package/dist/tools/editor/project_input_test.js +187 -0
- package/dist/tools/editor/resource.js +104 -0
- package/dist/tools/editor/scene.js +95 -0
- package/dist/tools/editor/shader.js +59 -0
- package/dist/tools/editor/signal.js +67 -0
- package/dist/tools/editor/spatial.js +185 -0
- package/dist/tools/editor/tiles.js +160 -0
- package/dist/tools/editor/ui.js +175 -0
- package/dist/tools/editor.js +39 -1914
- package/package.json +1 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** Scene-tree node authoring: add / delete / reparent / property / group ops. */
|
|
4
|
+
export function registerNodeTools(server, call) {
|
|
5
|
+
server.registerTool("node_add", {
|
|
6
|
+
title: "Add node",
|
|
7
|
+
description: "Instance a node of the given class under a parent path (undoable). Returns the new node's path.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
parent_path: z.string().describe("Parent node path relative to the scene root; \".\" for the root"),
|
|
10
|
+
type: z.string().describe("Node class to instance, e.g. Sprite2D, AudioStreamPlayer3D"),
|
|
11
|
+
name: z.string().optional().describe("Node name (defaults to the class name)"),
|
|
12
|
+
},
|
|
13
|
+
}, async ({ parent_path, type, name }) => call("node.add", { parent_path, type, name }));
|
|
14
|
+
server.registerTool("node_delete", {
|
|
15
|
+
title: "Delete node",
|
|
16
|
+
description: "Delete a node (undoable). DESTRUCTIVE — gated by confirmation. Refuses to delete the scene root.",
|
|
17
|
+
inputSchema: {
|
|
18
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
19
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
20
|
+
},
|
|
21
|
+
}, async ({ path, confirm }) => {
|
|
22
|
+
const blocked = await gate(server, confirm, `Delete node "${path}"`);
|
|
23
|
+
if (blocked)
|
|
24
|
+
return blocked;
|
|
25
|
+
return call("node.delete", { path });
|
|
26
|
+
});
|
|
27
|
+
server.registerTool("node_rename", {
|
|
28
|
+
title: "Rename node",
|
|
29
|
+
description: "Rename a node (undoable).",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
32
|
+
new_name: z.string().describe("New node name"),
|
|
33
|
+
},
|
|
34
|
+
}, async ({ path, new_name }) => call("node.rename", { path, new_name }));
|
|
35
|
+
server.registerTool("node_reparent", {
|
|
36
|
+
title: "Reparent node",
|
|
37
|
+
description: "Move a node under a new parent (undoable).",
|
|
38
|
+
inputSchema: {
|
|
39
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
40
|
+
new_parent_path: z.string().describe("New parent path; \".\" for the root"),
|
|
41
|
+
keep_global_transform: z.boolean().optional().describe("Preserve global transform (default true)"),
|
|
42
|
+
},
|
|
43
|
+
}, async ({ path, new_parent_path, keep_global_transform }) => call("node.reparent", { path, new_parent_path, keep_global_transform: keep_global_transform ?? true }));
|
|
44
|
+
server.registerTool("node_set_property", {
|
|
45
|
+
title: "Set node property",
|
|
46
|
+
description: "Set a property on a node (undoable). Rich types use the {\"__type__\":\"Vector3\",\"x\":..} convention. " +
|
|
47
|
+
"Example value for position: {\"__type__\":\"Vector3\",\"x\":1,\"y\":0,\"z\":2}.",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
50
|
+
property: z.string().describe("Property name, e.g. position, modulate, text"),
|
|
51
|
+
value: z.any().describe("New value (JSON scalar, array, object, or a __type__-tagged Variant)"),
|
|
52
|
+
},
|
|
53
|
+
}, async ({ path, property, value }) => call("node.set_property", { path, property, value }));
|
|
54
|
+
server.registerTool("node_get_property", {
|
|
55
|
+
title: "Get node property",
|
|
56
|
+
description: "Read a single property from a node. Rich types come back __type__-tagged.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
59
|
+
property: z.string().describe("Property name"),
|
|
60
|
+
},
|
|
61
|
+
}, async ({ path, property }) => call("node.get_property", { path, property }));
|
|
62
|
+
server.registerTool("node_duplicate", {
|
|
63
|
+
title: "Duplicate node",
|
|
64
|
+
description: "Duplicate a node and its children under the same parent (undoable). Returns the new node's path.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
67
|
+
name: z.string().optional().describe("Name for the duplicate (defaults to Godot's auto-numbered name)"),
|
|
68
|
+
},
|
|
69
|
+
}, async ({ path, name }) => call("node.duplicate", name !== undefined ? { path, name } : { path }));
|
|
70
|
+
server.registerTool("node_get_children", {
|
|
71
|
+
title: "Get node children",
|
|
72
|
+
description: "List the direct children of a node (name, type, path). Read-only.",
|
|
73
|
+
inputSchema: { path: z.string().describe("Node path relative to the scene root; \".\" for the root") },
|
|
74
|
+
}, async ({ path }) => call("node.get_children", { path }));
|
|
75
|
+
server.registerTool("node_find", {
|
|
76
|
+
title: "Find nodes",
|
|
77
|
+
description: "Search a node's descendants by class and/or name substring (case-insensitive). Read-only.",
|
|
78
|
+
inputSchema: {
|
|
79
|
+
root_path: z.string().optional().describe("Where to search from; \".\" or omitted for the scene root"),
|
|
80
|
+
type: z.string().optional().describe("Only match nodes of this class (is_class), e.g. Sprite2D"),
|
|
81
|
+
name_contains: z.string().optional().describe("Only match nodes whose name contains this substring"),
|
|
82
|
+
limit: z.number().int().positive().optional().describe("Max matches to return (default 200)"),
|
|
83
|
+
},
|
|
84
|
+
}, async ({ root_path, type, name_contains, limit }) => call("node.find", {
|
|
85
|
+
root_path: root_path ?? ".",
|
|
86
|
+
type: type ?? "",
|
|
87
|
+
name_contains: name_contains ?? "",
|
|
88
|
+
limit: limit ?? 200,
|
|
89
|
+
}));
|
|
90
|
+
server.registerTool("node_list_groups", {
|
|
91
|
+
title: "List node groups",
|
|
92
|
+
description: "List the groups a node belongs to. Read-only.",
|
|
93
|
+
inputSchema: { path: z.string().describe("Node path relative to the scene root") },
|
|
94
|
+
}, async ({ path }) => call("node.list_groups", { path }));
|
|
95
|
+
server.registerTool("node_add_to_group", {
|
|
96
|
+
title: "Add node to group",
|
|
97
|
+
description: "Add a node to a group (persistent, undoable). No-op if already a member.",
|
|
98
|
+
inputSchema: {
|
|
99
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
100
|
+
group: z.string().describe("Group name"),
|
|
101
|
+
},
|
|
102
|
+
}, async ({ path, group }) => call("node.add_to_group", { path, group }));
|
|
103
|
+
server.registerTool("node_remove_from_group", {
|
|
104
|
+
title: "Remove node from group",
|
|
105
|
+
description: "Remove a node from a group (undoable). No-op if not a member.",
|
|
106
|
+
inputSchema: {
|
|
107
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
108
|
+
group: z.string().describe("Group name"),
|
|
109
|
+
},
|
|
110
|
+
}, async ({ path, group }) => call("node.remove_from_group", { path, group }));
|
|
111
|
+
server.registerTool("node_instantiate_scene", {
|
|
112
|
+
title: "Instance scene under node",
|
|
113
|
+
description: "Instance an external PackedScene (res:// path) as an editable child of a parent node (undoable). Returns the new node's path.",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
parent_path: z.string().describe("Parent node path relative to the scene root; \".\" for the root"),
|
|
116
|
+
scene_path: z.string().describe("Scene to instance, e.g. res://actors/enemy.tscn"),
|
|
117
|
+
name: z.string().optional().describe("Node name (defaults to the instanced scene's root name)"),
|
|
118
|
+
},
|
|
119
|
+
}, async ({ parent_path, scene_path, name }) => call("node.instantiate_scene", name !== undefined ? { parent_path, scene_path, name } : { parent_path, scene_path }));
|
|
120
|
+
server.registerTool("node_move_child", {
|
|
121
|
+
title: "Move child",
|
|
122
|
+
description: "Reorder a node among its siblings by index (undoable). Negative indices count from the end (-1 = last).",
|
|
123
|
+
inputSchema: {
|
|
124
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
125
|
+
to_index: z.number().int().describe("New sibling index (0-based; negative counts from the end)"),
|
|
126
|
+
},
|
|
127
|
+
}, async ({ path, to_index }) => call("node.move_child", { path, to_index }));
|
|
128
|
+
server.registerTool("node_change_type", {
|
|
129
|
+
title: "Change node type",
|
|
130
|
+
description: "Replace a node with a new node of a different class, carrying over compatible properties, children, and groups (undoable). Refuses the scene root.",
|
|
131
|
+
inputSchema: {
|
|
132
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
133
|
+
type: z.string().describe("New node class, e.g. Sprite2D, StaticBody3D"),
|
|
134
|
+
},
|
|
135
|
+
}, async ({ path, type }) => call("node.change_type", { path, type }));
|
|
136
|
+
server.registerTool("node_set_owner", {
|
|
137
|
+
title: "Set node owner",
|
|
138
|
+
description: "Set a node's owner (undoable). Owner must be an ancestor; \".\" or omitted sets the scene root. Ownership determines which scene a node is saved into.",
|
|
139
|
+
inputSchema: {
|
|
140
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
141
|
+
owner_path: z.string().optional().describe("Ancestor to own the node; \".\" or omitted for the scene root"),
|
|
142
|
+
},
|
|
143
|
+
}, async ({ path, owner_path }) => call("node.set_owner", owner_path !== undefined ? { path, owner_path } : { path }));
|
|
144
|
+
server.registerTool("node_call_method", {
|
|
145
|
+
title: "Call node method (edit-time)",
|
|
146
|
+
description: "Invoke a method on a node in the EDITED scene. DESTRUCTIVE (arbitrary invocation, not undoable) — gated by confirmation. " +
|
|
147
|
+
"Args use the tagged-Variant convention; the return value comes back tagged.",
|
|
148
|
+
inputSchema: {
|
|
149
|
+
path: z.string().describe("Node path relative to the scene root"),
|
|
150
|
+
method: z.string().describe("Method name"),
|
|
151
|
+
args: z.array(z.any()).optional().describe("Positional arguments (JSON scalars or __type__-tagged Variants)"),
|
|
152
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
153
|
+
},
|
|
154
|
+
}, async ({ path, method, args, confirm }) => {
|
|
155
|
+
const blocked = await gate(server, confirm, `Call ${path}.${method}() in the edited scene`);
|
|
156
|
+
if (blocked)
|
|
157
|
+
return blocked;
|
|
158
|
+
return call("node.call_method", { path, method, args: args ?? [] });
|
|
159
|
+
});
|
|
160
|
+
server.registerTool("node_get_path", {
|
|
161
|
+
title: "Get node path",
|
|
162
|
+
description: "Return a node's scene-relative path, class, sibling index, parent path, and child count. Read-only.",
|
|
163
|
+
inputSchema: { path: z.string().describe("Node path relative to the scene root; \".\" for the root") },
|
|
164
|
+
}, async ({ path }) => call("node.get_path", { path }));
|
|
165
|
+
server.registerTool("node_list_properties", {
|
|
166
|
+
title: "List node properties",
|
|
167
|
+
description: "List a node's inspector-visible properties (name, Variant type, class_name, usage flags). Read-only. Use node_get_property to read a value.",
|
|
168
|
+
inputSchema: { path: z.string().describe("Node path relative to the scene root") },
|
|
169
|
+
}, async ({ path }) => call("node.list_properties", { path }));
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** GPUParticles authoring (process material, amount, lifetime, texture). */
|
|
3
|
+
export function registerParticleTools(server, call) {
|
|
4
|
+
server.registerTool("particles_create", {
|
|
5
|
+
title: "Create particles",
|
|
6
|
+
description: "Add a GPUParticles2D/3D node under a parent in the edited scene (undoable). Optional initial amount (> 0), lifetime (> 0), emitting. In-scene and undoable — not gated.",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
parent_path: z.string().describe("Parent node path relative to the scene root; \".\" for the root"),
|
|
9
|
+
dim: z.enum(["2d", "3d"]).optional().describe("Dimension: \"2d\" (default, GPUParticles2D) or \"3d\" (GPUParticles3D)"),
|
|
10
|
+
name: z.string().optional().describe("Node name (default \"GPUParticles2D\"/\"GPUParticles3D\")"),
|
|
11
|
+
amount: z.number().optional().describe("Number of particles (> 0, default 8)"),
|
|
12
|
+
lifetime: z.number().optional().describe("Particle lifetime in seconds (> 0, default 1)"),
|
|
13
|
+
emitting: z.boolean().optional().describe("Whether the system is emitting (default true)"),
|
|
14
|
+
},
|
|
15
|
+
}, async ({ parent_path, dim, name, amount, lifetime, emitting }) => {
|
|
16
|
+
const params = { parent_path };
|
|
17
|
+
if (dim !== undefined)
|
|
18
|
+
params.dim = dim;
|
|
19
|
+
if (name !== undefined)
|
|
20
|
+
params.name = name;
|
|
21
|
+
if (amount !== undefined)
|
|
22
|
+
params.amount = amount;
|
|
23
|
+
if (lifetime !== undefined)
|
|
24
|
+
params.lifetime = lifetime;
|
|
25
|
+
if (emitting !== undefined)
|
|
26
|
+
params.emitting = emitting;
|
|
27
|
+
return call("particles.create", params);
|
|
28
|
+
});
|
|
29
|
+
server.registerTool("particles_set_process_material", {
|
|
30
|
+
title: "Set particles process material",
|
|
31
|
+
description: "Create a ParticleProcessMaterial and assign it as process_material on a GPUParticles2D/3D in the edited scene (undoable). Optional knobs: gravity [x, y, z], direction [x, y, z], spread, initial_velocity_min/max, scale_min/max, color [r, g, b, a]. GPU particles need a process material to emit. In-scene and undoable — not gated.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
path: z.string().describe("GPUParticles2D/3D node path relative to the scene root"),
|
|
34
|
+
gravity: z.array(z.number()).optional().describe("Gravity vector [x, y, z]"),
|
|
35
|
+
direction: z.array(z.number()).optional().describe("Emission direction [x, y, z]"),
|
|
36
|
+
spread: z.number().optional().describe("Emission spread in degrees"),
|
|
37
|
+
initial_velocity_min: z.number().optional().describe("Minimum initial velocity"),
|
|
38
|
+
initial_velocity_max: z.number().optional().describe("Maximum initial velocity"),
|
|
39
|
+
scale_min: z.number().optional().describe("Minimum particle scale"),
|
|
40
|
+
scale_max: z.number().optional().describe("Maximum particle scale"),
|
|
41
|
+
color: z.array(z.number()).optional().describe("Base color [r, g, b] or [r, g, b, a] (0..1)"),
|
|
42
|
+
},
|
|
43
|
+
}, async ({ path, gravity, direction, spread, initial_velocity_min, initial_velocity_max, scale_min, scale_max, color }) => {
|
|
44
|
+
const params = { path };
|
|
45
|
+
if (gravity !== undefined)
|
|
46
|
+
params.gravity = gravity;
|
|
47
|
+
if (direction !== undefined)
|
|
48
|
+
params.direction = direction;
|
|
49
|
+
if (spread !== undefined)
|
|
50
|
+
params.spread = spread;
|
|
51
|
+
if (initial_velocity_min !== undefined)
|
|
52
|
+
params.initial_velocity_min = initial_velocity_min;
|
|
53
|
+
if (initial_velocity_max !== undefined)
|
|
54
|
+
params.initial_velocity_max = initial_velocity_max;
|
|
55
|
+
if (scale_min !== undefined)
|
|
56
|
+
params.scale_min = scale_min;
|
|
57
|
+
if (scale_max !== undefined)
|
|
58
|
+
params.scale_max = scale_max;
|
|
59
|
+
if (color !== undefined)
|
|
60
|
+
params.color = color;
|
|
61
|
+
return call("particles.set_process_material", params);
|
|
62
|
+
});
|
|
63
|
+
server.registerTool("particles_set_amount", {
|
|
64
|
+
title: "Set particles amount",
|
|
65
|
+
description: "Set the number of particles (amount, > 0) on a GPUParticles2D/3D in the edited scene (undoable). In-scene and undoable — not gated.",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
path: z.string().describe("GPUParticles2D/3D node path relative to the scene root"),
|
|
68
|
+
amount: z.number().describe("Number of particles (> 0)"),
|
|
69
|
+
},
|
|
70
|
+
}, async ({ path, amount }) => call("particles.set_amount", { path, amount }));
|
|
71
|
+
server.registerTool("particles_set_lifetime", {
|
|
72
|
+
title: "Set particles lifetime",
|
|
73
|
+
description: "Set the particle lifetime in seconds (> 0) on a GPUParticles2D/3D in the edited scene (undoable). In-scene and undoable — not gated.",
|
|
74
|
+
inputSchema: {
|
|
75
|
+
path: z.string().describe("GPUParticles2D/3D node path relative to the scene root"),
|
|
76
|
+
lifetime: z.number().describe("Lifetime in seconds (> 0)"),
|
|
77
|
+
},
|
|
78
|
+
}, async ({ path, lifetime }) => call("particles.set_lifetime", { path, lifetime }));
|
|
79
|
+
server.registerTool("particles_set_emitting", {
|
|
80
|
+
title: "Set particles emitting",
|
|
81
|
+
description: "Toggle whether a GPUParticles2D/3D is emitting in the edited scene (undoable). In-scene and undoable — not gated.",
|
|
82
|
+
inputSchema: {
|
|
83
|
+
path: z.string().describe("GPUParticles2D/3D node path relative to the scene root"),
|
|
84
|
+
emitting: z.boolean().describe("Whether the system is emitting"),
|
|
85
|
+
},
|
|
86
|
+
}, async ({ path, emitting }) => call("particles.set_emitting", { path, emitting }));
|
|
87
|
+
server.registerTool("particles_set_texture", {
|
|
88
|
+
title: "Set particles texture",
|
|
89
|
+
description: "Load a Texture2D from a res:// path and assign it as texture on a GPUParticles2D in the edited scene (undoable). GPUParticles2D only — GPUParticles3D draws meshes and has no texture (returns unsupported). In-scene and undoable — not gated.",
|
|
90
|
+
inputSchema: {
|
|
91
|
+
path: z.string().describe("GPUParticles2D node path relative to the scene root"),
|
|
92
|
+
texture_path: z.string().describe("res:// path to a Texture2D resource"),
|
|
93
|
+
},
|
|
94
|
+
}, async ({ path, texture_path }) => call("particles.set_texture", { path, texture_path }));
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=particles.js.map
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { gate } from "../../confirm.js";
|
|
3
|
+
/** Physics & collision: bodies, shapes, areas, joints, rigidbody tuning, gravity. */
|
|
4
|
+
export function registerPhysicsTools(server, call) {
|
|
5
|
+
server.registerTool("body_create", {
|
|
6
|
+
title: "Create physics body",
|
|
7
|
+
description: "Add a physics body node under a parent in the edited scene (undoable): a StaticBody, RigidBody, CharacterBody, or Area, in 2D or 3D. In-scene and undoable — not gated. Attach collision shapes with collisionshape_add.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
parent_path: z.string().describe("Parent node path relative to the scene root; \".\" for the root"),
|
|
10
|
+
type: z.enum(["static", "rigid", "character", "area"]).describe("Body kind: static | rigid | character | area"),
|
|
11
|
+
dim: z.enum(["2d", "3d"]).optional().describe("Dimension: \"2d\" (default) or \"3d\""),
|
|
12
|
+
name: z.string().optional().describe("Node name (default the class name, e.g. \"StaticBody2D\")"),
|
|
13
|
+
},
|
|
14
|
+
}, async ({ parent_path, type, dim, name }) => {
|
|
15
|
+
const params = { parent_path, type };
|
|
16
|
+
if (dim !== undefined)
|
|
17
|
+
params.dim = dim;
|
|
18
|
+
if (name !== undefined)
|
|
19
|
+
params.name = name;
|
|
20
|
+
return call("body.create", params);
|
|
21
|
+
});
|
|
22
|
+
server.registerTool("collisionshape_add", {
|
|
23
|
+
title: "Add collision shape",
|
|
24
|
+
description: "Add a CollisionShape2D/3D node carrying a shape resource under a parent (usually a body) in the edited scene (undoable). shape is rect | circle | capsule | polygon; dim selects 2D (Rectangle/Circle/Capsule/ConvexPolygon 2D) or 3D (Box/Sphere/Capsule/ConvexPolygon 3D). In-scene and undoable — not gated.",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
parent_path: z.string().describe("Parent node path (usually a body) relative to the scene root; \".\" for the root"),
|
|
27
|
+
shape: z.enum(["rect", "circle", "capsule", "polygon"]).describe("Shape kind: rect | circle | capsule | polygon"),
|
|
28
|
+
dim: z.enum(["2d", "3d"]).optional().describe("Dimension: \"2d\" (default) or \"3d\""),
|
|
29
|
+
name: z.string().optional().describe("Node name (default \"CollisionShape2D\"/\"CollisionShape3D\")"),
|
|
30
|
+
size: z.array(z.number()).optional().describe("rect: [w, h] (2D) or [w, h, d] (3D)"),
|
|
31
|
+
radius: z.number().optional().describe("circle/capsule radius"),
|
|
32
|
+
height: z.number().optional().describe("capsule height"),
|
|
33
|
+
points: z.array(z.array(z.number())).optional().describe("polygon: convex-hull points, [[x, y], …] (2D, ≥3) or [[x, y, z], …] (3D, ≥4)"),
|
|
34
|
+
},
|
|
35
|
+
}, async ({ parent_path, shape, dim, name, size, radius, height, points }) => {
|
|
36
|
+
const params = { parent_path, shape };
|
|
37
|
+
if (dim !== undefined)
|
|
38
|
+
params.dim = dim;
|
|
39
|
+
if (name !== undefined)
|
|
40
|
+
params.name = name;
|
|
41
|
+
if (size !== undefined)
|
|
42
|
+
params.size = size;
|
|
43
|
+
if (radius !== undefined)
|
|
44
|
+
params.radius = radius;
|
|
45
|
+
if (height !== undefined)
|
|
46
|
+
params.height = height;
|
|
47
|
+
if (points !== undefined)
|
|
48
|
+
params.points = points;
|
|
49
|
+
return call("collisionshape.add", params);
|
|
50
|
+
});
|
|
51
|
+
server.registerTool("body_set_collision_layer", {
|
|
52
|
+
title: "Set collision layer",
|
|
53
|
+
description: "Set the collision_layer bitmask on a physics body or area (CollisionObject2D/3D) in the edited scene (undoable). layer is the integer bitmask of layers this object occupies.",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
path: z.string().describe("Body/Area node path relative to the scene root"),
|
|
56
|
+
layer: z.number().int().describe("collision_layer bitmask (non-negative integer)"),
|
|
57
|
+
},
|
|
58
|
+
}, async ({ path, layer }) => call("body.set_collision_layer", { path, layer }));
|
|
59
|
+
server.registerTool("body_set_collision_mask", {
|
|
60
|
+
title: "Set collision mask",
|
|
61
|
+
description: "Set the collision_mask bitmask on a physics body or area (CollisionObject2D/3D) in the edited scene (undoable). mask is the integer bitmask of layers this object scans for collisions.",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
path: z.string().describe("Body/Area node path relative to the scene root"),
|
|
64
|
+
mask: z.number().int().describe("collision_mask bitmask (non-negative integer)"),
|
|
65
|
+
},
|
|
66
|
+
}, async ({ path, mask }) => call("body.set_collision_mask", { path, mask }));
|
|
67
|
+
server.registerTool("area_set_monitoring", {
|
|
68
|
+
title: "Set area monitoring",
|
|
69
|
+
description: "Set monitoring and/or monitorable on an Area2D/3D in the edited scene (undoable). monitoring = the area detects overlapping bodies/areas; monitorable = other areas can detect it. In-scene and undoable — not gated.",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
path: z.string().describe("Area2D/3D node path relative to the scene root"),
|
|
72
|
+
monitoring: z.boolean().optional().describe("Whether the area detects overlapping bodies/areas"),
|
|
73
|
+
monitorable: z.boolean().optional().describe("Whether other areas can detect this area"),
|
|
74
|
+
},
|
|
75
|
+
}, async ({ path, monitoring, monitorable }) => {
|
|
76
|
+
const params = { path };
|
|
77
|
+
if (monitoring !== undefined)
|
|
78
|
+
params.monitoring = monitoring;
|
|
79
|
+
if (monitorable !== undefined)
|
|
80
|
+
params.monitorable = monitorable;
|
|
81
|
+
return call("area.set_monitoring", params);
|
|
82
|
+
});
|
|
83
|
+
server.registerTool("area_set_gravity", {
|
|
84
|
+
title: "Set area gravity",
|
|
85
|
+
description: "Set the local gravity override of an Area2D/3D in the edited scene (undoable): space_override mode, gravity magnitude, direction, and whether gravity points toward a center (point). In-scene and undoable — not gated.",
|
|
86
|
+
inputSchema: {
|
|
87
|
+
path: z.string().describe("Area2D/3D node path relative to the scene root"),
|
|
88
|
+
space_override: z.enum(["disabled", "combine", "combine_replace", "replace", "replace_combine"]).optional().describe("How this area's gravity combines with the global/other areas"),
|
|
89
|
+
gravity: z.number().optional().describe("Gravity magnitude (units/s^2)"),
|
|
90
|
+
direction: z.array(z.number()).optional().describe("Gravity direction [x, y] (2D) or [x, y, z] (3D)"),
|
|
91
|
+
point: z.boolean().optional().describe("If true, gravity pulls toward the area's gravity point instead of a direction"),
|
|
92
|
+
},
|
|
93
|
+
}, async ({ path, space_override, gravity, direction, point }) => {
|
|
94
|
+
const params = { path };
|
|
95
|
+
if (space_override !== undefined)
|
|
96
|
+
params.space_override = space_override;
|
|
97
|
+
if (gravity !== undefined)
|
|
98
|
+
params.gravity = gravity;
|
|
99
|
+
if (direction !== undefined)
|
|
100
|
+
params.direction = direction;
|
|
101
|
+
if (point !== undefined)
|
|
102
|
+
params.point = point;
|
|
103
|
+
return call("area.set_gravity", params);
|
|
104
|
+
});
|
|
105
|
+
server.registerTool("joint_create", {
|
|
106
|
+
title: "Create physics joint",
|
|
107
|
+
description: "Add a physics joint node under a parent in the edited scene (undoable). 2D types: pin | groove | spring (PinJoint2D/GrooveJoint2D/DampedSpringJoint2D); 3D types: pin | hinge | slider | cone_twist | generic6dof (PinJoint3D/HingeJoint3D/SliderJoint3D/ConeTwistJoint3D/Generic6DOFJoint3D). Optionally wire node_a/node_b to the two bodies. In-scene and undoable — not gated.",
|
|
108
|
+
inputSchema: {
|
|
109
|
+
parent_path: z.string().describe("Parent node path relative to the scene root; \".\" for the root"),
|
|
110
|
+
type: z.enum(["pin", "groove", "spring", "hinge", "slider", "cone_twist", "generic6dof"]).describe("Joint kind; pin works in both dims, the rest are dim-specific"),
|
|
111
|
+
dim: z.enum(["2d", "3d"]).optional().describe("Dimension: \"2d\" (default) or \"3d\""),
|
|
112
|
+
name: z.string().optional().describe("Node name (default the class name, e.g. \"PinJoint2D\")"),
|
|
113
|
+
node_a: z.string().optional().describe("NodePath (relative to the joint) of the first body"),
|
|
114
|
+
node_b: z.string().optional().describe("NodePath (relative to the joint) of the second body"),
|
|
115
|
+
},
|
|
116
|
+
}, async ({ parent_path, type, dim, name, node_a, node_b }) => {
|
|
117
|
+
const params = { parent_path, type };
|
|
118
|
+
if (dim !== undefined)
|
|
119
|
+
params.dim = dim;
|
|
120
|
+
if (name !== undefined)
|
|
121
|
+
params.name = name;
|
|
122
|
+
if (node_a !== undefined)
|
|
123
|
+
params.node_a = node_a;
|
|
124
|
+
if (node_b !== undefined)
|
|
125
|
+
params.node_b = node_b;
|
|
126
|
+
return call("joint.create", params);
|
|
127
|
+
});
|
|
128
|
+
server.registerTool("joint_set_bodies", {
|
|
129
|
+
title: "Set joint bodies",
|
|
130
|
+
description: "Set node_a and/or node_b on an existing Joint2D/3D in the edited scene (undoable) — the NodePaths of the two bodies the joint connects, relative to the joint node. In-scene and undoable — not gated.",
|
|
131
|
+
inputSchema: {
|
|
132
|
+
path: z.string().describe("Joint2D/3D node path relative to the scene root"),
|
|
133
|
+
node_a: z.string().optional().describe("NodePath (relative to the joint) of the first body"),
|
|
134
|
+
node_b: z.string().optional().describe("NodePath (relative to the joint) of the second body"),
|
|
135
|
+
},
|
|
136
|
+
}, async ({ path, node_a, node_b }) => {
|
|
137
|
+
const params = { path };
|
|
138
|
+
if (node_a !== undefined)
|
|
139
|
+
params.node_a = node_a;
|
|
140
|
+
if (node_b !== undefined)
|
|
141
|
+
params.node_b = node_b;
|
|
142
|
+
return call("joint.set_bodies", params);
|
|
143
|
+
});
|
|
144
|
+
server.registerTool("collisionpolygon_add", {
|
|
145
|
+
title: "Add collision polygon",
|
|
146
|
+
description: "Add a CollisionPolygon2D/3D node carrying a polygon under a parent (usually a body) in the edited scene (undoable). points is a 2D outline [[x, y], …] (≥3); for 3D it is extruded along Z by depth. 2D build_mode is solids | segments. In-scene and undoable — not gated.",
|
|
147
|
+
inputSchema: {
|
|
148
|
+
parent_path: z.string().describe("Parent node path (usually a body) relative to the scene root; \".\" for the root"),
|
|
149
|
+
points: z.array(z.array(z.number())).describe("Polygon outline points [[x, y], …] (≥3); a 2D outline even for 3D"),
|
|
150
|
+
dim: z.enum(["2d", "3d"]).optional().describe("Dimension: \"2d\" (default) or \"3d\""),
|
|
151
|
+
name: z.string().optional().describe("Node name (default \"CollisionPolygon2D\"/\"CollisionPolygon3D\")"),
|
|
152
|
+
build_mode: z.enum(["solids", "segments"]).optional().describe("2D only: solids (default) or segments"),
|
|
153
|
+
depth: z.number().optional().describe("3D only: extrusion depth along Z (default 1.0)"),
|
|
154
|
+
},
|
|
155
|
+
}, async ({ parent_path, points, dim, name, build_mode, depth }) => {
|
|
156
|
+
const params = { parent_path, points };
|
|
157
|
+
if (dim !== undefined)
|
|
158
|
+
params.dim = dim;
|
|
159
|
+
if (name !== undefined)
|
|
160
|
+
params.name = name;
|
|
161
|
+
if (build_mode !== undefined)
|
|
162
|
+
params.build_mode = build_mode;
|
|
163
|
+
if (depth !== undefined)
|
|
164
|
+
params.depth = depth;
|
|
165
|
+
return call("collisionpolygon.add", params);
|
|
166
|
+
});
|
|
167
|
+
server.registerTool("rigidbody_set_properties", {
|
|
168
|
+
title: "Set rigidbody properties",
|
|
169
|
+
description: "Tune a RigidBody2D/3D in the edited scene (undoable): mass (> 0), gravity_scale, linear_damp, angular_damp. Only the provided properties change. In-scene and undoable — not gated.",
|
|
170
|
+
inputSchema: {
|
|
171
|
+
path: z.string().describe("RigidBody2D/3D node path relative to the scene root"),
|
|
172
|
+
mass: z.number().optional().describe("Body mass (> 0)"),
|
|
173
|
+
gravity_scale: z.number().optional().describe("Multiplier on gravity (1 = normal, 0 = float)"),
|
|
174
|
+
linear_damp: z.number().optional().describe("Linear damping (≥ 0)"),
|
|
175
|
+
angular_damp: z.number().optional().describe("Angular damping (≥ 0)"),
|
|
176
|
+
},
|
|
177
|
+
}, async ({ path, mass, gravity_scale, linear_damp, angular_damp }) => {
|
|
178
|
+
const params = { path };
|
|
179
|
+
if (mass !== undefined)
|
|
180
|
+
params.mass = mass;
|
|
181
|
+
if (gravity_scale !== undefined)
|
|
182
|
+
params.gravity_scale = gravity_scale;
|
|
183
|
+
if (linear_damp !== undefined)
|
|
184
|
+
params.linear_damp = linear_damp;
|
|
185
|
+
if (angular_damp !== undefined)
|
|
186
|
+
params.angular_damp = angular_damp;
|
|
187
|
+
return call("rigidbody.set_properties", params);
|
|
188
|
+
});
|
|
189
|
+
server.registerTool("body_set_physics_material", {
|
|
190
|
+
title: "Set body physics material",
|
|
191
|
+
description: "Create a PhysicsMaterial and assign it as physics_material_override on a StaticBody/RigidBody (2D or 3D) in the edited scene (undoable): friction (default 1), bounce (default 0), rough, absorbent. In-scene and undoable — not gated.",
|
|
192
|
+
inputSchema: {
|
|
193
|
+
path: z.string().describe("StaticBody/RigidBody 2D/3D node path relative to the scene root"),
|
|
194
|
+
friction: z.number().optional().describe("Surface friction 0..1 (default 1)"),
|
|
195
|
+
bounce: z.number().optional().describe("Restitution/bounciness 0..1 (default 0)"),
|
|
196
|
+
rough: z.boolean().optional().describe("Rough friction combine mode (default false)"),
|
|
197
|
+
absorbent: z.boolean().optional().describe("Absorbent bounce combine mode (default false)"),
|
|
198
|
+
},
|
|
199
|
+
}, async ({ path, friction, bounce, rough, absorbent }) => {
|
|
200
|
+
const params = { path };
|
|
201
|
+
if (friction !== undefined)
|
|
202
|
+
params.friction = friction;
|
|
203
|
+
if (bounce !== undefined)
|
|
204
|
+
params.bounce = bounce;
|
|
205
|
+
if (rough !== undefined)
|
|
206
|
+
params.rough = rough;
|
|
207
|
+
if (absorbent !== undefined)
|
|
208
|
+
params.absorbent = absorbent;
|
|
209
|
+
return call("body.set_physics_material", params);
|
|
210
|
+
});
|
|
211
|
+
server.registerTool("physics_set_gravity", {
|
|
212
|
+
title: "Set project gravity",
|
|
213
|
+
description: "Write the project's default gravity for 2D or 3D (ProjectSettings physics/{2d,3d}/default_gravity + default_gravity_vector). Set save=true to persist to project.godot. DESTRUCTIVE (project-wide setting) — gated by confirmation.",
|
|
214
|
+
inputSchema: {
|
|
215
|
+
dim: z.enum(["2d", "3d"]).optional().describe("Which gravity to set: \"2d\" (default) or \"3d\""),
|
|
216
|
+
magnitude: z.number().optional().describe("Gravity magnitude (default 2D 980, 3D 9.8)"),
|
|
217
|
+
direction: z.array(z.number()).optional().describe("Gravity direction vector [x, y] (2D) or [x, y, z] (3D)"),
|
|
218
|
+
save: z.boolean().optional().describe("Persist to project.godot (default false)"),
|
|
219
|
+
confirm: z.boolean().optional().describe("Auto-approve this destructive action (skip the confirmation prompt)"),
|
|
220
|
+
},
|
|
221
|
+
}, async ({ dim, magnitude, direction, save, confirm }) => {
|
|
222
|
+
const blocked = await gate(server, confirm, `Set project ${dim ?? "2d"} gravity${save ? " and save project.godot" : ""}`);
|
|
223
|
+
if (blocked)
|
|
224
|
+
return blocked;
|
|
225
|
+
const params = {};
|
|
226
|
+
if (dim !== undefined)
|
|
227
|
+
params.dim = dim;
|
|
228
|
+
if (magnitude !== undefined)
|
|
229
|
+
params.magnitude = magnitude;
|
|
230
|
+
if (direction !== undefined)
|
|
231
|
+
params.direction = direction;
|
|
232
|
+
params.save = save ?? false;
|
|
233
|
+
return call("physics.set_gravity", params);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=physics.js.map
|