mcpforunityserver 9.4.0b20260203025228__py3-none-any.whl
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.
- cli/__init__.py +3 -0
- cli/commands/__init__.py +3 -0
- cli/commands/animation.py +84 -0
- cli/commands/asset.py +280 -0
- cli/commands/audio.py +125 -0
- cli/commands/batch.py +171 -0
- cli/commands/code.py +182 -0
- cli/commands/component.py +190 -0
- cli/commands/editor.py +447 -0
- cli/commands/gameobject.py +487 -0
- cli/commands/instance.py +93 -0
- cli/commands/lighting.py +123 -0
- cli/commands/material.py +239 -0
- cli/commands/prefab.py +248 -0
- cli/commands/scene.py +231 -0
- cli/commands/script.py +222 -0
- cli/commands/shader.py +226 -0
- cli/commands/texture.py +540 -0
- cli/commands/tool.py +58 -0
- cli/commands/ui.py +258 -0
- cli/commands/vfx.py +421 -0
- cli/main.py +281 -0
- cli/utils/__init__.py +31 -0
- cli/utils/config.py +58 -0
- cli/utils/confirmation.py +37 -0
- cli/utils/connection.py +254 -0
- cli/utils/constants.py +23 -0
- cli/utils/output.py +195 -0
- cli/utils/parsers.py +112 -0
- cli/utils/suggestions.py +34 -0
- core/__init__.py +0 -0
- core/config.py +67 -0
- core/constants.py +4 -0
- core/logging_decorator.py +37 -0
- core/telemetry.py +551 -0
- core/telemetry_decorator.py +164 -0
- main.py +845 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/METADATA +328 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/RECORD +105 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/WHEEL +5 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/entry_points.txt +3 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/licenses/LICENSE +21 -0
- mcpforunityserver-9.4.0b20260203025228.dist-info/top_level.txt +7 -0
- models/__init__.py +4 -0
- models/models.py +56 -0
- models/unity_response.py +70 -0
- services/__init__.py +0 -0
- services/api_key_service.py +235 -0
- services/custom_tool_service.py +499 -0
- services/registry/__init__.py +22 -0
- services/registry/resource_registry.py +53 -0
- services/registry/tool_registry.py +51 -0
- services/resources/__init__.py +86 -0
- services/resources/active_tool.py +48 -0
- services/resources/custom_tools.py +57 -0
- services/resources/editor_state.py +304 -0
- services/resources/gameobject.py +243 -0
- services/resources/layers.py +30 -0
- services/resources/menu_items.py +35 -0
- services/resources/prefab.py +191 -0
- services/resources/prefab_stage.py +40 -0
- services/resources/project_info.py +40 -0
- services/resources/selection.py +56 -0
- services/resources/tags.py +31 -0
- services/resources/tests.py +88 -0
- services/resources/unity_instances.py +125 -0
- services/resources/windows.py +48 -0
- services/state/external_changes_scanner.py +245 -0
- services/tools/__init__.py +83 -0
- services/tools/batch_execute.py +93 -0
- services/tools/debug_request_context.py +86 -0
- services/tools/execute_custom_tool.py +43 -0
- services/tools/execute_menu_item.py +32 -0
- services/tools/find_gameobjects.py +110 -0
- services/tools/find_in_file.py +181 -0
- services/tools/manage_asset.py +119 -0
- services/tools/manage_components.py +131 -0
- services/tools/manage_editor.py +64 -0
- services/tools/manage_gameobject.py +260 -0
- services/tools/manage_material.py +111 -0
- services/tools/manage_prefabs.py +209 -0
- services/tools/manage_scene.py +111 -0
- services/tools/manage_script.py +645 -0
- services/tools/manage_scriptable_object.py +87 -0
- services/tools/manage_shader.py +71 -0
- services/tools/manage_texture.py +581 -0
- services/tools/manage_vfx.py +120 -0
- services/tools/preflight.py +110 -0
- services/tools/read_console.py +151 -0
- services/tools/refresh_unity.py +153 -0
- services/tools/run_tests.py +317 -0
- services/tools/script_apply_edits.py +1006 -0
- services/tools/set_active_instance.py +120 -0
- services/tools/utils.py +348 -0
- transport/__init__.py +0 -0
- transport/legacy/port_discovery.py +329 -0
- transport/legacy/stdio_port_registry.py +65 -0
- transport/legacy/unity_connection.py +910 -0
- transport/models.py +68 -0
- transport/plugin_hub.py +787 -0
- transport/plugin_registry.py +182 -0
- transport/unity_instance_middleware.py +262 -0
- transport/unity_transport.py +94 -0
- utils/focus_nudge.py +589 -0
- utils/module_discovery.py +55 -0
cli/commands/ui.py
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""UI CLI commands - placeholder for future implementation."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import click
|
|
5
|
+
from typing import Optional, Any
|
|
6
|
+
|
|
7
|
+
from cli.utils.config import get_config
|
|
8
|
+
from cli.utils.output import format_output, print_error, print_success
|
|
9
|
+
from cli.utils.connection import run_command, handle_unity_errors
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.group()
|
|
13
|
+
def ui():
|
|
14
|
+
"""UI operations - create and modify UI elements."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@ui.command("create-canvas")
|
|
19
|
+
@click.argument("name")
|
|
20
|
+
@click.option(
|
|
21
|
+
"--render-mode",
|
|
22
|
+
type=click.Choice(
|
|
23
|
+
["ScreenSpaceOverlay", "ScreenSpaceCamera", "WorldSpace"]),
|
|
24
|
+
default="ScreenSpaceOverlay",
|
|
25
|
+
help="Canvas render mode."
|
|
26
|
+
)
|
|
27
|
+
@handle_unity_errors
|
|
28
|
+
def create_canvas(name: str, render_mode: str):
|
|
29
|
+
"""Create a new Canvas.
|
|
30
|
+
|
|
31
|
+
\b
|
|
32
|
+
Examples:
|
|
33
|
+
unity-mcp ui create-canvas "MainUI"
|
|
34
|
+
unity-mcp ui create-canvas "WorldUI" --render-mode WorldSpace
|
|
35
|
+
"""
|
|
36
|
+
config = get_config()
|
|
37
|
+
|
|
38
|
+
# Step 1: Create empty GameObject
|
|
39
|
+
result = run_command("manage_gameobject", {
|
|
40
|
+
"action": "create",
|
|
41
|
+
"name": name,
|
|
42
|
+
}, config)
|
|
43
|
+
|
|
44
|
+
if not (result.get("success") or result.get("data") or result.get("result")):
|
|
45
|
+
click.echo(format_output(result, config.format))
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
# Step 2: Add Canvas components
|
|
49
|
+
failed_components = []
|
|
50
|
+
for component in ["Canvas", "CanvasScaler", "GraphicRaycaster"]:
|
|
51
|
+
comp_result = run_command("manage_components", {
|
|
52
|
+
"action": "add",
|
|
53
|
+
"target": name,
|
|
54
|
+
"componentType": component,
|
|
55
|
+
}, config)
|
|
56
|
+
if not (comp_result.get("success") or comp_result.get("data")):
|
|
57
|
+
failed_components.append((component, comp_result.get("error", "Unknown error")))
|
|
58
|
+
|
|
59
|
+
if failed_components:
|
|
60
|
+
error_details = "; ".join([f"{c}: {e}" for c, e in failed_components])
|
|
61
|
+
print_error(f"Failed to add components: {error_details}")
|
|
62
|
+
|
|
63
|
+
# Step 3: Set render mode
|
|
64
|
+
render_mode_value = {"ScreenSpaceOverlay": 0,
|
|
65
|
+
"ScreenSpaceCamera": 1, "WorldSpace": 2}.get(render_mode, 0)
|
|
66
|
+
run_command("manage_components", {
|
|
67
|
+
"action": "set_property",
|
|
68
|
+
"target": name,
|
|
69
|
+
"componentType": "Canvas",
|
|
70
|
+
"property": "renderMode",
|
|
71
|
+
"value": render_mode_value,
|
|
72
|
+
}, config)
|
|
73
|
+
|
|
74
|
+
click.echo(format_output(result, config.format))
|
|
75
|
+
print_success(f"Created Canvas: {name}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@ui.command("create-text")
|
|
79
|
+
@click.argument("name")
|
|
80
|
+
@click.option(
|
|
81
|
+
"--parent", "-p",
|
|
82
|
+
required=True,
|
|
83
|
+
help="Parent Canvas or UI element."
|
|
84
|
+
)
|
|
85
|
+
@click.option(
|
|
86
|
+
"--text", "-t",
|
|
87
|
+
default="New Text",
|
|
88
|
+
help="Initial text content."
|
|
89
|
+
)
|
|
90
|
+
@click.option(
|
|
91
|
+
"--position",
|
|
92
|
+
nargs=2,
|
|
93
|
+
type=float,
|
|
94
|
+
default=(0, 0),
|
|
95
|
+
help="Anchored position X Y."
|
|
96
|
+
)
|
|
97
|
+
@handle_unity_errors
|
|
98
|
+
def create_text(name: str, parent: str, text: str, position: tuple):
|
|
99
|
+
"""Create a UI Text element (TextMeshPro).
|
|
100
|
+
|
|
101
|
+
\b
|
|
102
|
+
Examples:
|
|
103
|
+
unity-mcp ui create-text "TitleText" --parent "MainUI" --text "Hello World"
|
|
104
|
+
"""
|
|
105
|
+
config = get_config()
|
|
106
|
+
|
|
107
|
+
# Step 1: Create empty GameObject with parent
|
|
108
|
+
result = run_command("manage_gameobject", {
|
|
109
|
+
"action": "create",
|
|
110
|
+
"name": name,
|
|
111
|
+
"parent": parent,
|
|
112
|
+
"position": list(position),
|
|
113
|
+
}, config)
|
|
114
|
+
|
|
115
|
+
if not (result.get("success") or result.get("data") or result.get("result")):
|
|
116
|
+
click.echo(format_output(result, config.format))
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
# Step 2: Add RectTransform and TextMeshProUGUI
|
|
120
|
+
run_command("manage_components", {
|
|
121
|
+
"action": "add",
|
|
122
|
+
"target": name,
|
|
123
|
+
"componentType": "TextMeshProUGUI",
|
|
124
|
+
}, config)
|
|
125
|
+
|
|
126
|
+
# Step 3: Set text content
|
|
127
|
+
run_command("manage_components", {
|
|
128
|
+
"action": "set_property",
|
|
129
|
+
"target": name,
|
|
130
|
+
"componentType": "TextMeshProUGUI",
|
|
131
|
+
"property": "text",
|
|
132
|
+
"value": text,
|
|
133
|
+
}, config)
|
|
134
|
+
|
|
135
|
+
click.echo(format_output(result, config.format))
|
|
136
|
+
print_success(f"Created Text: {name}")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@ui.command("create-button")
|
|
140
|
+
@click.argument("name")
|
|
141
|
+
@click.option(
|
|
142
|
+
"--parent", "-p",
|
|
143
|
+
required=True,
|
|
144
|
+
help="Parent Canvas or UI element."
|
|
145
|
+
)
|
|
146
|
+
@click.option(
|
|
147
|
+
"--text", "-t",
|
|
148
|
+
default="Button",
|
|
149
|
+
help="Button label text."
|
|
150
|
+
)
|
|
151
|
+
@handle_unity_errors
|
|
152
|
+
def create_button(name: str, parent: str, text: str): # text current placeholder
|
|
153
|
+
"""Create a UI Button.
|
|
154
|
+
|
|
155
|
+
\b
|
|
156
|
+
Examples:
|
|
157
|
+
unity-mcp ui create-button "StartButton" --parent "MainUI" --text "Start Game"
|
|
158
|
+
"""
|
|
159
|
+
config = get_config()
|
|
160
|
+
|
|
161
|
+
# Step 1: Create empty GameObject with parent
|
|
162
|
+
result = run_command("manage_gameobject", {
|
|
163
|
+
"action": "create",
|
|
164
|
+
"name": name,
|
|
165
|
+
"parent": parent,
|
|
166
|
+
}, config)
|
|
167
|
+
|
|
168
|
+
if not (result.get("success") or result.get("data") or result.get("result")):
|
|
169
|
+
click.echo(format_output(result, config.format))
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
# Step 2: Add Button and Image components
|
|
173
|
+
for component in ["Image", "Button"]:
|
|
174
|
+
run_command("manage_components", {
|
|
175
|
+
"action": "add",
|
|
176
|
+
"target": name,
|
|
177
|
+
"componentType": component,
|
|
178
|
+
}, config)
|
|
179
|
+
|
|
180
|
+
# Step 3: Create child label GameObject
|
|
181
|
+
label_name = f"{name}_Label"
|
|
182
|
+
run_command("manage_gameobject", {
|
|
183
|
+
"action": "create",
|
|
184
|
+
"name": label_name,
|
|
185
|
+
"parent": name,
|
|
186
|
+
}, config)
|
|
187
|
+
|
|
188
|
+
# Step 4: Add TextMeshProUGUI to label and set text
|
|
189
|
+
run_command("manage_components", {
|
|
190
|
+
"action": "add",
|
|
191
|
+
"target": label_name,
|
|
192
|
+
"componentType": "TextMeshProUGUI",
|
|
193
|
+
}, config)
|
|
194
|
+
run_command("manage_components", {
|
|
195
|
+
"action": "set_property",
|
|
196
|
+
"target": label_name,
|
|
197
|
+
"componentType": "TextMeshProUGUI",
|
|
198
|
+
"property": "text",
|
|
199
|
+
"value": text,
|
|
200
|
+
}, config)
|
|
201
|
+
|
|
202
|
+
click.echo(format_output(result, config.format))
|
|
203
|
+
print_success(f"Created Button: {name} (with label '{text}')")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
@ui.command("create-image")
|
|
207
|
+
@click.argument("name")
|
|
208
|
+
@click.option(
|
|
209
|
+
"--parent", "-p",
|
|
210
|
+
required=True,
|
|
211
|
+
help="Parent Canvas or UI element."
|
|
212
|
+
)
|
|
213
|
+
@click.option(
|
|
214
|
+
"--sprite", "-s",
|
|
215
|
+
default=None,
|
|
216
|
+
help="Sprite asset path."
|
|
217
|
+
)
|
|
218
|
+
@handle_unity_errors
|
|
219
|
+
def create_image(name: str, parent: str, sprite: Optional[str]):
|
|
220
|
+
"""Create a UI Image.
|
|
221
|
+
|
|
222
|
+
\b
|
|
223
|
+
Examples:
|
|
224
|
+
unity-mcp ui create-image "Background" --parent "MainUI"
|
|
225
|
+
unity-mcp ui create-image "Icon" --parent "MainUI" --sprite "Assets/Sprites/icon.png"
|
|
226
|
+
"""
|
|
227
|
+
config = get_config()
|
|
228
|
+
|
|
229
|
+
# Step 1: Create empty GameObject with parent
|
|
230
|
+
result = run_command("manage_gameobject", {
|
|
231
|
+
"action": "create",
|
|
232
|
+
"name": name,
|
|
233
|
+
"parent": parent,
|
|
234
|
+
}, config)
|
|
235
|
+
|
|
236
|
+
if not (result.get("success") or result.get("data") or result.get("result")):
|
|
237
|
+
click.echo(format_output(result, config.format))
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
# Step 2: Add Image component
|
|
241
|
+
run_command("manage_components", {
|
|
242
|
+
"action": "add",
|
|
243
|
+
"target": name,
|
|
244
|
+
"componentType": "Image",
|
|
245
|
+
}, config)
|
|
246
|
+
|
|
247
|
+
# Step 3: Set sprite if provided
|
|
248
|
+
if sprite:
|
|
249
|
+
run_command("manage_components", {
|
|
250
|
+
"action": "set_property",
|
|
251
|
+
"target": name,
|
|
252
|
+
"componentType": "Image",
|
|
253
|
+
"property": "sprite",
|
|
254
|
+
"value": sprite,
|
|
255
|
+
}, config)
|
|
256
|
+
|
|
257
|
+
click.echo(format_output(result, config.format))
|
|
258
|
+
print_success(f"Created Image: {name}")
|
cli/commands/vfx.py
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
"""VFX CLI commands for managing Unity visual effects."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import json
|
|
5
|
+
import click
|
|
6
|
+
from typing import Optional, Tuple, Any
|
|
7
|
+
|
|
8
|
+
from cli.utils.config import get_config
|
|
9
|
+
from cli.utils.output import format_output, print_error, print_success
|
|
10
|
+
from cli.utils.connection import run_command, handle_unity_errors
|
|
11
|
+
from cli.utils.parsers import parse_json_list_or_exit, parse_json_dict_or_exit
|
|
12
|
+
from cli.utils.constants import SEARCH_METHOD_CHOICE_TAGGED
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
_VFX_TOP_LEVEL_KEYS = {"action", "target", "searchMethod", "properties"}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _normalize_vfx_params(params: dict[str, Any]) -> dict[str, Any]:
|
|
19
|
+
params = dict(params)
|
|
20
|
+
properties: dict[str, Any] = {}
|
|
21
|
+
for key in list(params.keys()):
|
|
22
|
+
if key in _VFX_TOP_LEVEL_KEYS:
|
|
23
|
+
continue
|
|
24
|
+
properties[key] = params.pop(key)
|
|
25
|
+
|
|
26
|
+
if properties:
|
|
27
|
+
existing = params.get("properties")
|
|
28
|
+
if isinstance(existing, dict):
|
|
29
|
+
params["properties"] = {**properties, **existing}
|
|
30
|
+
else:
|
|
31
|
+
params["properties"] = properties
|
|
32
|
+
|
|
33
|
+
return {k: v for k, v in params.items() if v is not None}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@click.group()
|
|
37
|
+
def vfx():
|
|
38
|
+
"""VFX operations - particle systems, line renderers, trails."""
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# =============================================================================
|
|
43
|
+
# Particle System Commands
|
|
44
|
+
# =============================================================================
|
|
45
|
+
|
|
46
|
+
@vfx.group()
|
|
47
|
+
def particle():
|
|
48
|
+
"""Particle system operations."""
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@particle.command("info")
|
|
53
|
+
@click.argument("target")
|
|
54
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
55
|
+
@handle_unity_errors
|
|
56
|
+
def particle_info(target: str, search_method: Optional[str]):
|
|
57
|
+
"""Get particle system info.
|
|
58
|
+
|
|
59
|
+
\\b
|
|
60
|
+
Examples:
|
|
61
|
+
unity-mcp vfx particle info "Fire"
|
|
62
|
+
unity-mcp vfx particle info "-12345" --search-method by_id
|
|
63
|
+
"""
|
|
64
|
+
config = get_config()
|
|
65
|
+
params: dict[str, Any] = {"action": "particle_get_info", "target": target}
|
|
66
|
+
if search_method:
|
|
67
|
+
params["searchMethod"] = search_method
|
|
68
|
+
|
|
69
|
+
result = run_command(
|
|
70
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
71
|
+
click.echo(format_output(result, config.format))
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@particle.command("play")
|
|
75
|
+
@click.argument("target")
|
|
76
|
+
@click.option("--with-children", is_flag=True, help="Also play child particle systems.")
|
|
77
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
78
|
+
@handle_unity_errors
|
|
79
|
+
def particle_play(target: str, with_children: bool, search_method: Optional[str]):
|
|
80
|
+
"""Play a particle system.
|
|
81
|
+
|
|
82
|
+
\\b
|
|
83
|
+
Examples:
|
|
84
|
+
unity-mcp vfx particle play "Fire"
|
|
85
|
+
unity-mcp vfx particle play "Effects" --with-children
|
|
86
|
+
"""
|
|
87
|
+
config = get_config()
|
|
88
|
+
params: dict[str, Any] = {"action": "particle_play", "target": target}
|
|
89
|
+
if with_children:
|
|
90
|
+
params["withChildren"] = True
|
|
91
|
+
if search_method:
|
|
92
|
+
params["searchMethod"] = search_method
|
|
93
|
+
|
|
94
|
+
result = run_command(
|
|
95
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
96
|
+
click.echo(format_output(result, config.format))
|
|
97
|
+
if result.get("success"):
|
|
98
|
+
print_success(f"Playing particle system: {target}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@particle.command("stop")
|
|
102
|
+
@click.argument("target")
|
|
103
|
+
@click.option("--with-children", is_flag=True, help="Also stop child particle systems.")
|
|
104
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
105
|
+
@handle_unity_errors
|
|
106
|
+
def particle_stop(target: str, with_children: bool, search_method: Optional[str]):
|
|
107
|
+
"""Stop a particle system."""
|
|
108
|
+
config = get_config()
|
|
109
|
+
params: dict[str, Any] = {"action": "particle_stop", "target": target}
|
|
110
|
+
if with_children:
|
|
111
|
+
params["withChildren"] = True
|
|
112
|
+
if search_method:
|
|
113
|
+
params["searchMethod"] = search_method
|
|
114
|
+
|
|
115
|
+
result = run_command(
|
|
116
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
117
|
+
click.echo(format_output(result, config.format))
|
|
118
|
+
if result.get("success"):
|
|
119
|
+
print_success(f"Stopped particle system: {target}")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@particle.command("pause")
|
|
123
|
+
@click.argument("target")
|
|
124
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
125
|
+
@handle_unity_errors
|
|
126
|
+
def particle_pause(target: str, search_method: Optional[str]):
|
|
127
|
+
"""Pause a particle system."""
|
|
128
|
+
config = get_config()
|
|
129
|
+
params: dict[str, Any] = {"action": "particle_pause", "target": target}
|
|
130
|
+
if search_method:
|
|
131
|
+
params["searchMethod"] = search_method
|
|
132
|
+
|
|
133
|
+
result = run_command(
|
|
134
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
135
|
+
click.echo(format_output(result, config.format))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@particle.command("restart")
|
|
139
|
+
@click.argument("target")
|
|
140
|
+
@click.option("--with-children", is_flag=True)
|
|
141
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
142
|
+
@handle_unity_errors
|
|
143
|
+
def particle_restart(target: str, with_children: bool, search_method: Optional[str]):
|
|
144
|
+
"""Restart a particle system."""
|
|
145
|
+
config = get_config()
|
|
146
|
+
params: dict[str, Any] = {"action": "particle_restart", "target": target}
|
|
147
|
+
if with_children:
|
|
148
|
+
params["withChildren"] = True
|
|
149
|
+
if search_method:
|
|
150
|
+
params["searchMethod"] = search_method
|
|
151
|
+
|
|
152
|
+
result = run_command(
|
|
153
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
154
|
+
click.echo(format_output(result, config.format))
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@particle.command("clear")
|
|
158
|
+
@click.argument("target")
|
|
159
|
+
@click.option("--with-children", is_flag=True)
|
|
160
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
161
|
+
@handle_unity_errors
|
|
162
|
+
def particle_clear(target: str, with_children: bool, search_method: Optional[str]):
|
|
163
|
+
"""Clear all particles from a particle system."""
|
|
164
|
+
config = get_config()
|
|
165
|
+
params: dict[str, Any] = {"action": "particle_clear", "target": target}
|
|
166
|
+
if with_children:
|
|
167
|
+
params["withChildren"] = True
|
|
168
|
+
if search_method:
|
|
169
|
+
params["searchMethod"] = search_method
|
|
170
|
+
|
|
171
|
+
result = run_command(
|
|
172
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
173
|
+
click.echo(format_output(result, config.format))
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# =============================================================================
|
|
177
|
+
# Line Renderer Commands
|
|
178
|
+
# =============================================================================
|
|
179
|
+
|
|
180
|
+
@vfx.group()
|
|
181
|
+
def line():
|
|
182
|
+
"""Line renderer operations."""
|
|
183
|
+
pass
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@line.command("info")
|
|
187
|
+
@click.argument("target")
|
|
188
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
189
|
+
@handle_unity_errors
|
|
190
|
+
def line_info(target: str, search_method: Optional[str]):
|
|
191
|
+
"""Get line renderer info.
|
|
192
|
+
|
|
193
|
+
\\b
|
|
194
|
+
Examples:
|
|
195
|
+
unity-mcp vfx line info "LaserBeam"
|
|
196
|
+
"""
|
|
197
|
+
config = get_config()
|
|
198
|
+
params: dict[str, Any] = {"action": "line_get_info", "target": target}
|
|
199
|
+
if search_method:
|
|
200
|
+
params["searchMethod"] = search_method
|
|
201
|
+
|
|
202
|
+
result = run_command(
|
|
203
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
204
|
+
click.echo(format_output(result, config.format))
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@line.command("set-positions")
|
|
208
|
+
@click.argument("target")
|
|
209
|
+
@click.option("--positions", "-p", required=True, help='Positions as JSON array: [[0,0,0], [1,1,1], [2,0,0]]')
|
|
210
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
211
|
+
@handle_unity_errors
|
|
212
|
+
def line_set_positions(target: str, positions: str, search_method: Optional[str]):
|
|
213
|
+
"""Set all positions on a line renderer.
|
|
214
|
+
|
|
215
|
+
\\b
|
|
216
|
+
Examples:
|
|
217
|
+
unity-mcp vfx line set-positions "Line" --positions "[[0,0,0], [5,2,0], [10,0,0]]"
|
|
218
|
+
"""
|
|
219
|
+
config = get_config()
|
|
220
|
+
|
|
221
|
+
positions_list = parse_json_list_or_exit(positions, "positions")
|
|
222
|
+
|
|
223
|
+
params: dict[str, Any] = {
|
|
224
|
+
"action": "line_set_positions",
|
|
225
|
+
"target": target,
|
|
226
|
+
"positions": positions_list,
|
|
227
|
+
}
|
|
228
|
+
if search_method:
|
|
229
|
+
params["searchMethod"] = search_method
|
|
230
|
+
|
|
231
|
+
result = run_command(
|
|
232
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
233
|
+
click.echo(format_output(result, config.format))
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@line.command("create-line")
|
|
237
|
+
@click.argument("target")
|
|
238
|
+
@click.option("--start", nargs=3, type=float, required=True, help="Start point X Y Z")
|
|
239
|
+
@click.option("--end", nargs=3, type=float, required=True, help="End point X Y Z")
|
|
240
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
241
|
+
@handle_unity_errors
|
|
242
|
+
def line_create_line(target: str, start: Tuple[float, float, float], end: Tuple[float, float, float], search_method: Optional[str]):
|
|
243
|
+
"""Create a simple line between two points.
|
|
244
|
+
|
|
245
|
+
\\b
|
|
246
|
+
Examples:
|
|
247
|
+
unity-mcp vfx line create-line "MyLine" --start 0 0 0 --end 10 5 0
|
|
248
|
+
"""
|
|
249
|
+
config = get_config()
|
|
250
|
+
params: dict[str, Any] = {
|
|
251
|
+
"action": "line_create_line",
|
|
252
|
+
"target": target,
|
|
253
|
+
"start": list(start),
|
|
254
|
+
"end": list(end),
|
|
255
|
+
}
|
|
256
|
+
if search_method:
|
|
257
|
+
params["searchMethod"] = search_method
|
|
258
|
+
|
|
259
|
+
result = run_command(
|
|
260
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
261
|
+
click.echo(format_output(result, config.format))
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@line.command("create-circle")
|
|
265
|
+
@click.argument("target")
|
|
266
|
+
@click.option("--center", nargs=3, type=float, default=(0, 0, 0), help="Center point X Y Z")
|
|
267
|
+
@click.option("--radius", type=float, required=True, help="Circle radius")
|
|
268
|
+
@click.option("--segments", type=int, default=32, help="Number of segments")
|
|
269
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
270
|
+
@handle_unity_errors
|
|
271
|
+
def line_create_circle(target: str, center: Tuple[float, float, float], radius: float, segments: int, search_method: Optional[str]):
|
|
272
|
+
"""Create a circle shape.
|
|
273
|
+
|
|
274
|
+
\\b
|
|
275
|
+
Examples:
|
|
276
|
+
unity-mcp vfx line create-circle "Circle" --radius 5 --segments 64
|
|
277
|
+
unity-mcp vfx line create-circle "Ring" --center 0 2 0 --radius 3
|
|
278
|
+
"""
|
|
279
|
+
config = get_config()
|
|
280
|
+
params: dict[str, Any] = {
|
|
281
|
+
"action": "line_create_circle",
|
|
282
|
+
"target": target,
|
|
283
|
+
"center": list(center),
|
|
284
|
+
"radius": radius,
|
|
285
|
+
"segments": segments,
|
|
286
|
+
}
|
|
287
|
+
if search_method:
|
|
288
|
+
params["searchMethod"] = search_method
|
|
289
|
+
|
|
290
|
+
result = run_command(
|
|
291
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
292
|
+
click.echo(format_output(result, config.format))
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
@line.command("clear")
|
|
296
|
+
@click.argument("target")
|
|
297
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
298
|
+
@handle_unity_errors
|
|
299
|
+
def line_clear(target: str, search_method: Optional[str]):
|
|
300
|
+
"""Clear all positions from a line renderer."""
|
|
301
|
+
config = get_config()
|
|
302
|
+
params: dict[str, Any] = {"action": "line_clear", "target": target}
|
|
303
|
+
if search_method:
|
|
304
|
+
params["searchMethod"] = search_method
|
|
305
|
+
|
|
306
|
+
result = run_command(
|
|
307
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
308
|
+
click.echo(format_output(result, config.format))
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# =============================================================================
|
|
312
|
+
# Trail Renderer Commands
|
|
313
|
+
# =============================================================================
|
|
314
|
+
|
|
315
|
+
@vfx.group()
|
|
316
|
+
def trail():
|
|
317
|
+
"""Trail renderer operations."""
|
|
318
|
+
pass
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
@trail.command("info")
|
|
322
|
+
@click.argument("target")
|
|
323
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
324
|
+
@handle_unity_errors
|
|
325
|
+
def trail_info(target: str, search_method: Optional[str]):
|
|
326
|
+
"""Get trail renderer info."""
|
|
327
|
+
config = get_config()
|
|
328
|
+
params: dict[str, Any] = {"action": "trail_get_info", "target": target}
|
|
329
|
+
if search_method:
|
|
330
|
+
params["searchMethod"] = search_method
|
|
331
|
+
|
|
332
|
+
result = run_command(
|
|
333
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
334
|
+
click.echo(format_output(result, config.format))
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
@trail.command("set-time")
|
|
338
|
+
@click.argument("target")
|
|
339
|
+
@click.argument("duration", type=float)
|
|
340
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
341
|
+
@handle_unity_errors
|
|
342
|
+
def trail_set_time(target: str, duration: float, search_method: Optional[str]):
|
|
343
|
+
"""Set trail duration.
|
|
344
|
+
|
|
345
|
+
\\b
|
|
346
|
+
Examples:
|
|
347
|
+
unity-mcp vfx trail set-time "PlayerTrail" 2.0
|
|
348
|
+
"""
|
|
349
|
+
config = get_config()
|
|
350
|
+
params: dict[str, Any] = {
|
|
351
|
+
"action": "trail_set_time",
|
|
352
|
+
"target": target,
|
|
353
|
+
"time": duration,
|
|
354
|
+
}
|
|
355
|
+
if search_method:
|
|
356
|
+
params["searchMethod"] = search_method
|
|
357
|
+
|
|
358
|
+
result = run_command(
|
|
359
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
360
|
+
click.echo(format_output(result, config.format))
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
@trail.command("clear")
|
|
364
|
+
@click.argument("target")
|
|
365
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
366
|
+
@handle_unity_errors
|
|
367
|
+
def trail_clear(target: str, search_method: Optional[str]):
|
|
368
|
+
"""Clear a trail renderer."""
|
|
369
|
+
config = get_config()
|
|
370
|
+
params: dict[str, Any] = {"action": "trail_clear", "target": target}
|
|
371
|
+
if search_method:
|
|
372
|
+
params["searchMethod"] = search_method
|
|
373
|
+
|
|
374
|
+
result = run_command(
|
|
375
|
+
"manage_vfx", _normalize_vfx_params(params), config)
|
|
376
|
+
click.echo(format_output(result, config.format))
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
# =============================================================================
|
|
380
|
+
# Raw Command (escape hatch for all VFX actions)
|
|
381
|
+
# =============================================================================
|
|
382
|
+
|
|
383
|
+
@vfx.command("raw")
|
|
384
|
+
@click.argument("action")
|
|
385
|
+
@click.argument("target", required=False)
|
|
386
|
+
@click.option("--params", "-p", default="{}", help="Additional parameters as JSON.")
|
|
387
|
+
@click.option("--search-method", type=SEARCH_METHOD_CHOICE_TAGGED, default=None)
|
|
388
|
+
@handle_unity_errors
|
|
389
|
+
def vfx_raw(action: str, target: Optional[str], params: str, search_method: Optional[str]):
|
|
390
|
+
"""Execute any VFX action directly.
|
|
391
|
+
|
|
392
|
+
For advanced users who need access to all 60+ VFX actions.
|
|
393
|
+
|
|
394
|
+
\\b
|
|
395
|
+
Actions include:
|
|
396
|
+
particle_*: particle_set_main, particle_set_emission, particle_set_shape, ...
|
|
397
|
+
vfx_*: vfx_set_float, vfx_send_event, vfx_play, ...
|
|
398
|
+
line_*: line_create_arc, line_create_bezier, ...
|
|
399
|
+
trail_*: trail_set_width, trail_set_color, ...
|
|
400
|
+
|
|
401
|
+
\\b
|
|
402
|
+
Examples:
|
|
403
|
+
unity-mcp vfx raw particle_set_main "Fire" --params '{"duration": 5, "looping": true}'
|
|
404
|
+
unity-mcp vfx raw line_create_arc "Arc" --params '{"radius": 3, "startAngle": 0, "endAngle": 180}'
|
|
405
|
+
unity-mcp vfx raw vfx_send_event "Explosion" --params '{"eventName": "OnSpawn"}'
|
|
406
|
+
"""
|
|
407
|
+
config = get_config()
|
|
408
|
+
|
|
409
|
+
extra_params = parse_json_dict_or_exit(params, "params")
|
|
410
|
+
|
|
411
|
+
request_params: dict[str, Any] = {"action": action}
|
|
412
|
+
if target:
|
|
413
|
+
request_params["target"] = target
|
|
414
|
+
if search_method:
|
|
415
|
+
request_params["searchMethod"] = search_method
|
|
416
|
+
|
|
417
|
+
# Merge extra params
|
|
418
|
+
request_params.update(extra_params)
|
|
419
|
+
result = run_command(
|
|
420
|
+
"manage_vfx", _normalize_vfx_params(request_params), config)
|
|
421
|
+
click.echo(format_output(result, config.format))
|