@akiojin/unity-mcp-server 2.14.14
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/LICENSE +21 -0
- package/README.md +206 -0
- package/bin/unity-mcp-server +2 -0
- package/package.json +73 -0
- package/src/core/codeIndex.js +163 -0
- package/src/core/codeIndexDb.js +96 -0
- package/src/core/config.js +165 -0
- package/src/core/indexWatcher.js +52 -0
- package/src/core/projectInfo.js +111 -0
- package/src/core/server.js +294 -0
- package/src/core/unityConnection.js +426 -0
- package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +35 -0
- package/src/handlers/analysis/FindByComponentToolHandler.js +20 -0
- package/src/handlers/analysis/GetAnimatorStateToolHandler.js +37 -0
- package/src/handlers/analysis/GetComponentValuesToolHandler.js +20 -0
- package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +35 -0
- package/src/handlers/analysis/GetInputActionsStateToolHandler.js +37 -0
- package/src/handlers/analysis/GetObjectReferencesToolHandler.js +20 -0
- package/src/handlers/asset/AssetDatabaseToolHandler.js +221 -0
- package/src/handlers/asset/AssetDependencyToolHandler.js +201 -0
- package/src/handlers/asset/AssetImportSettingsToolHandler.js +170 -0
- package/src/handlers/asset/CreateMaterialToolHandler.js +96 -0
- package/src/handlers/asset/CreatePrefabToolHandler.js +78 -0
- package/src/handlers/asset/ExitPrefabModeToolHandler.js +83 -0
- package/src/handlers/asset/InstantiatePrefabToolHandler.js +133 -0
- package/src/handlers/asset/ModifyMaterialToolHandler.js +76 -0
- package/src/handlers/asset/ModifyPrefabToolHandler.js +72 -0
- package/src/handlers/asset/OpenPrefabToolHandler.js +121 -0
- package/src/handlers/asset/SavePrefabToolHandler.js +106 -0
- package/src/handlers/base/BaseToolHandler.js +133 -0
- package/src/handlers/compilation/GetCompilationStateToolHandler.js +90 -0
- package/src/handlers/component/AddComponentToolHandler.js +126 -0
- package/src/handlers/component/GetComponentTypesToolHandler.js +100 -0
- package/src/handlers/component/ListComponentsToolHandler.js +85 -0
- package/src/handlers/component/ModifyComponentToolHandler.js +143 -0
- package/src/handlers/component/RemoveComponentToolHandler.js +108 -0
- package/src/handlers/console/ClearConsoleToolHandler.js +160 -0
- package/src/handlers/console/ReadConsoleToolHandler.js +276 -0
- package/src/handlers/editor/LayerManagementToolHandler.js +160 -0
- package/src/handlers/editor/SelectionToolHandler.js +141 -0
- package/src/handlers/editor/TagManagementToolHandler.js +129 -0
- package/src/handlers/editor/ToolManagementToolHandler.js +135 -0
- package/src/handlers/editor/WindowManagementToolHandler.js +125 -0
- package/src/handlers/gameobject/CreateGameObjectToolHandler.js +131 -0
- package/src/handlers/gameobject/DeleteGameObjectToolHandler.js +101 -0
- package/src/handlers/gameobject/FindGameObjectToolHandler.js +119 -0
- package/src/handlers/gameobject/GetHierarchyToolHandler.js +132 -0
- package/src/handlers/gameobject/ModifyGameObjectToolHandler.js +128 -0
- package/src/handlers/index.js +389 -0
- package/src/handlers/input/AddInputActionToolHandler.js +20 -0
- package/src/handlers/input/AddInputBindingToolHandler.js +20 -0
- package/src/handlers/input/CreateActionMapToolHandler.js +20 -0
- package/src/handlers/input/CreateCompositeBindingToolHandler.js +20 -0
- package/src/handlers/input/GamepadSimulationHandler.js +116 -0
- package/src/handlers/input/InputSystemHandler.js +80 -0
- package/src/handlers/input/KeyboardSimulationHandler.js +79 -0
- package/src/handlers/input/ManageControlSchemesToolHandler.js +20 -0
- package/src/handlers/input/MouseSimulationHandler.js +107 -0
- package/src/handlers/input/RemoveActionMapToolHandler.js +20 -0
- package/src/handlers/input/RemoveAllBindingsToolHandler.js +20 -0
- package/src/handlers/input/RemoveInputActionToolHandler.js +20 -0
- package/src/handlers/input/RemoveInputBindingToolHandler.js +20 -0
- package/src/handlers/input/TouchSimulationHandler.js +142 -0
- package/src/handlers/menu/ExecuteMenuItemToolHandler.js +304 -0
- package/src/handlers/package/PackageManagerToolHandler.js +248 -0
- package/src/handlers/package/RegistryConfigToolHandler.js +198 -0
- package/src/handlers/playmode/GetEditorStateToolHandler.js +81 -0
- package/src/handlers/playmode/PauseToolHandler.js +44 -0
- package/src/handlers/playmode/PlayToolHandler.js +91 -0
- package/src/handlers/playmode/StopToolHandler.js +77 -0
- package/src/handlers/playmode/WaitForEditorStateToolHandler.js +45 -0
- package/src/handlers/scene/CreateSceneToolHandler.js +91 -0
- package/src/handlers/scene/GetSceneInfoToolHandler.js +20 -0
- package/src/handlers/scene/ListScenesToolHandler.js +58 -0
- package/src/handlers/scene/LoadSceneToolHandler.js +92 -0
- package/src/handlers/scene/SaveSceneToolHandler.js +76 -0
- package/src/handlers/screenshot/AnalyzeScreenshotToolHandler.js +238 -0
- package/src/handlers/screenshot/CaptureScreenshotToolHandler.js +692 -0
- package/src/handlers/script/BuildCodeIndexToolHandler.js +163 -0
- package/src/handlers/script/ScriptCreateClassFileToolHandler.js +60 -0
- package/src/handlers/script/ScriptEditStructuredToolHandler.js +173 -0
- package/src/handlers/script/ScriptIndexStatusToolHandler.js +61 -0
- package/src/handlers/script/ScriptPackagesListToolHandler.js +103 -0
- package/src/handlers/script/ScriptReadToolHandler.js +106 -0
- package/src/handlers/script/ScriptRefactorRenameToolHandler.js +83 -0
- package/src/handlers/script/ScriptRefsFindToolHandler.js +144 -0
- package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +79 -0
- package/src/handlers/script/ScriptSearchToolHandler.js +320 -0
- package/src/handlers/script/ScriptSymbolFindToolHandler.js +117 -0
- package/src/handlers/script/ScriptSymbolsGetToolHandler.js +96 -0
- package/src/handlers/settings/GetProjectSettingsToolHandler.js +161 -0
- package/src/handlers/settings/UpdateProjectSettingsToolHandler.js +272 -0
- package/src/handlers/system/GetCommandStatsToolHandler.js +25 -0
- package/src/handlers/system/PingToolHandler.js +53 -0
- package/src/handlers/system/RefreshAssetsToolHandler.js +45 -0
- package/src/handlers/ui/ClickUIElementToolHandler.js +110 -0
- package/src/handlers/ui/FindUIElementsToolHandler.js +63 -0
- package/src/handlers/ui/GetUIElementStateToolHandler.js +50 -0
- package/src/handlers/ui/SetUIElementValueToolHandler.js +49 -0
- package/src/handlers/ui/SimulateUIInputToolHandler.js +156 -0
- package/src/handlers/video/CaptureVideoForToolHandler.js +96 -0
- package/src/handlers/video/CaptureVideoStartToolHandler.js +38 -0
- package/src/handlers/video/CaptureVideoStatusToolHandler.js +30 -0
- package/src/handlers/video/CaptureVideoStopToolHandler.js +32 -0
- package/src/lsp/CSharpLspUtils.js +134 -0
- package/src/lsp/LspProcessManager.js +60 -0
- package/src/lsp/LspRpcClient.js +133 -0
- package/src/tools/analysis/analyzeSceneContents.js +100 -0
- package/src/tools/analysis/findByComponent.js +87 -0
- package/src/tools/analysis/getAnimatorState.js +326 -0
- package/src/tools/analysis/getComponentValues.js +182 -0
- package/src/tools/analysis/getGameObjectDetails.js +159 -0
- package/src/tools/analysis/getInputActionsState.js +329 -0
- package/src/tools/analysis/getObjectReferences.js +86 -0
- package/src/tools/input/inputActionsEditor.js +556 -0
- package/src/tools/scene/createScene.js +112 -0
- package/src/tools/scene/getSceneInfo.js +95 -0
- package/src/tools/scene/listScenes.js +82 -0
- package/src/tools/scene/loadScene.js +122 -0
- package/src/tools/scene/saveScene.js +91 -0
- package/src/tools/system/ping.js +72 -0
- package/src/tools/video/recordFor.js +31 -0
- package/src/tools/video/recordPlayMode.js +61 -0
- package/src/utils/csharpParse.js +88 -0
- package/src/utils/validators.js +90 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
3
|
+
import { CodeIndex } from '../../core/codeIndex.js';
|
|
4
|
+
import { LspRpcClient } from '../../lsp/LspRpcClient.js';
|
|
5
|
+
import { ProjectInfoProvider } from '../../core/projectInfo.js';
|
|
6
|
+
|
|
7
|
+
export class ScriptSymbolFindToolHandler extends BaseToolHandler {
|
|
8
|
+
constructor(unityConnection) {
|
|
9
|
+
super(
|
|
10
|
+
'script_symbol_find',
|
|
11
|
+
'Find symbol definitions by name (class/method/field/property) using the bundled C# LSP. Guidance: prefer narrowing by kind and set exact=true when possible; use scope=assets|packages to avoid large outputs. Use results (container, namespace) to construct container namePath like Outer/Nested/Member for subsequent edit tools.',
|
|
12
|
+
{
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
name: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: 'Symbol name to search (exact or fuzzy based on "exact").'
|
|
18
|
+
},
|
|
19
|
+
kind: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'Optional: narrow by symbol kind (class, method, field, property).'
|
|
22
|
+
},
|
|
23
|
+
scope: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
enum: ['assets', 'packages', 'embedded', 'all'],
|
|
26
|
+
description: 'Search scope: assets (Assets/), packages (Packages/), embedded, or all (default: all).'
|
|
27
|
+
},
|
|
28
|
+
exact: {
|
|
29
|
+
type: 'boolean',
|
|
30
|
+
description: 'If true, match name exactly; otherwise allows partial matches (default: false).'
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
required: ['name']
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
this.unityConnection = unityConnection;
|
|
37
|
+
this.index = new CodeIndex(unityConnection);
|
|
38
|
+
this.projectInfo = new ProjectInfoProvider(unityConnection);
|
|
39
|
+
this.lsp = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
validate(params) {
|
|
43
|
+
super.validate(params);
|
|
44
|
+
|
|
45
|
+
const { name } = params;
|
|
46
|
+
|
|
47
|
+
if (!name || name.trim() === '') {
|
|
48
|
+
throw new Error('name cannot be empty');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async execute(params) {
|
|
53
|
+
const { name, kind, scope = 'assets', exact = false } = params;
|
|
54
|
+
// Prefer persistent index if available
|
|
55
|
+
let results = [];
|
|
56
|
+
if (await this.index.isReady()) {
|
|
57
|
+
const rows = await this.index.querySymbols({ name, kind, scope, exact });
|
|
58
|
+
results = rows.map(r => ({
|
|
59
|
+
path: r.path,
|
|
60
|
+
symbol: {
|
|
61
|
+
name: r.name,
|
|
62
|
+
kind: r.kind,
|
|
63
|
+
namespace: r.ns,
|
|
64
|
+
container: r.container,
|
|
65
|
+
startLine: r.line,
|
|
66
|
+
startColumn: r.column,
|
|
67
|
+
endLine: r.line,
|
|
68
|
+
endColumn: r.column
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
} else {
|
|
72
|
+
const info = await this.projectInfo.get();
|
|
73
|
+
if (!this.lsp) this.lsp = new LspRpcClient(info.projectRoot);
|
|
74
|
+
const resp = await this.lsp.request('workspace/symbol', { query: String(name) });
|
|
75
|
+
const arr = resp?.result || [];
|
|
76
|
+
results = arr.map(s => ({
|
|
77
|
+
path: (s.location?.uri || '').replace('file://',''),
|
|
78
|
+
symbol: {
|
|
79
|
+
name: s.name,
|
|
80
|
+
kind: this.mapKind(s.kind),
|
|
81
|
+
namespace: null,
|
|
82
|
+
container: null,
|
|
83
|
+
startLine: (s.location?.range?.start?.line ?? 0) + 1,
|
|
84
|
+
startColumn: (s.location?.range?.start?.character ?? 0) + 1,
|
|
85
|
+
endLine: (s.location?.range?.end?.line ?? 0) + 1,
|
|
86
|
+
endColumn: (s.location?.range?.end?.character ?? 0) + 1,
|
|
87
|
+
}
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
// Optional post-filtering: scope and exact name
|
|
91
|
+
if (scope && scope !== 'all') {
|
|
92
|
+
results = results.filter(x => {
|
|
93
|
+
const p = (x.path || '').replace(/\\\\/g, '/');
|
|
94
|
+
switch (scope) {
|
|
95
|
+
case 'assets': return p.startsWith('Assets/');
|
|
96
|
+
case 'packages': return p.startsWith('Packages/') || p.startsWith('Library/PackageCache/');
|
|
97
|
+
case 'embedded': return p.startsWith('Packages/'); }
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (exact) {
|
|
101
|
+
const target = String(name);
|
|
102
|
+
results = results.filter(x => x.symbol && x.symbol.name === target);
|
|
103
|
+
}
|
|
104
|
+
return { success: true, results, total: results.length };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
mapKind(k) {
|
|
108
|
+
switch(k){
|
|
109
|
+
case 5: return 'class';
|
|
110
|
+
case 23: return 'struct';
|
|
111
|
+
case 11: return 'interface';
|
|
112
|
+
case 10: return 'enum';
|
|
113
|
+
case 6: return 'method';
|
|
114
|
+
case 7: return 'property';
|
|
115
|
+
case 8: return 'field'; }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
4
|
+
import { ProjectInfoProvider } from '../../core/projectInfo.js';
|
|
5
|
+
|
|
6
|
+
export class ScriptSymbolsGetToolHandler extends BaseToolHandler {
|
|
7
|
+
constructor(unityConnection) {
|
|
8
|
+
super(
|
|
9
|
+
'script_symbols_get',
|
|
10
|
+
'FIRST STEP: Identify symbols (classes, methods, fields, properties) with spans before any edit. Path must start with Assets/ or Packages/. Use this to scope changes to a single symbol and avoid line-based edits. Returns line/column positions and container names (helpful to build container namePath like Outer/Nested/Member).',
|
|
11
|
+
{
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
path: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Project-relative .cs path under Assets/ or Packages/ (e.g., Packages/unity-mcp-server/Editor/Foo.cs). Do NOT prefix repository folders (e.g., UnityMCPServer/…).'
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
required: ['path']
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
this.unityConnection = unityConnection;
|
|
23
|
+
this.projectInfo = new ProjectInfoProvider(unityConnection);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
validate(params) {
|
|
27
|
+
super.validate(params);
|
|
28
|
+
|
|
29
|
+
const { path } = params;
|
|
30
|
+
|
|
31
|
+
if (!path || path.trim() === '') {
|
|
32
|
+
throw new Error('path cannot be empty');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Check for .cs extension
|
|
36
|
+
if (!path.endsWith('.cs')) {
|
|
37
|
+
throw new Error('Only .cs files are supported');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async execute(params) {
|
|
42
|
+
// Normalize to project-relative path (strip repo-root prefixes if provided)
|
|
43
|
+
const rawPath = String(params.path || '').replace(/\\/g, '/');
|
|
44
|
+
const ai = rawPath.indexOf('Assets/');
|
|
45
|
+
const pi = rawPath.indexOf('Packages/');
|
|
46
|
+
const cut = (ai >= 0 && pi >= 0) ? Math.min(ai, pi) : (ai >= 0 ? ai : pi);
|
|
47
|
+
const relPath = cut >= 0 ? rawPath.substring(cut) : rawPath;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const info = await this.projectInfo.get();
|
|
51
|
+
if (!relPath.startsWith('Assets/') && !relPath.startsWith('Packages/')) {
|
|
52
|
+
return { error: 'Path must be under Assets/ or Packages/' };
|
|
53
|
+
}
|
|
54
|
+
const abs = path.join(info.projectRoot, relPath);
|
|
55
|
+
const st = await fs.stat(abs).catch(() => null);
|
|
56
|
+
if (!st || !st.isFile()) return { error: 'File not found', path: relPath };
|
|
57
|
+
const { LspRpcClient } = await import('../../lsp/LspRpcClient.js');
|
|
58
|
+
const lsp = new LspRpcClient(info.projectRoot);
|
|
59
|
+
const uri = 'file://' + abs.replace(/\\\\/g, '/');
|
|
60
|
+
const res = await lsp.request('textDocument/documentSymbol', { textDocument: { uri } });
|
|
61
|
+
const docSymbols = res?.result ?? res ?? [];
|
|
62
|
+
const list = [];
|
|
63
|
+
const visit = (s, container) => {
|
|
64
|
+
const start = s.range?.start || s.selectionRange?.start || {};
|
|
65
|
+
list.push({
|
|
66
|
+
name: s.name || '',
|
|
67
|
+
kind: this.mapKind(s.kind),
|
|
68
|
+
container: container || null,
|
|
69
|
+
namespace: null,
|
|
70
|
+
startLine: (start.line ?? 0) + 1,
|
|
71
|
+
startColumn: (start.character ?? 0) + 1,
|
|
72
|
+
endLine: (start.line ?? 0) + 1,
|
|
73
|
+
endColumn: (start.character ?? 0) + 1
|
|
74
|
+
});
|
|
75
|
+
if (Array.isArray(s.children)) for (const c of s.children) visit(c, s.name || container);
|
|
76
|
+
};
|
|
77
|
+
if (Array.isArray(docSymbols)) for (const s of docSymbols) visit(s, null);
|
|
78
|
+
return { success: true, path: relPath, symbols: list };
|
|
79
|
+
} catch (e) {
|
|
80
|
+
return { error: e.message || 'Failed to get symbols' };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
mapKind(k) {
|
|
85
|
+
switch (k) {
|
|
86
|
+
case 5: return 'class';
|
|
87
|
+
case 23: return 'struct';
|
|
88
|
+
case 11: return 'interface';
|
|
89
|
+
case 10: return 'enum';
|
|
90
|
+
case 6: return 'method';
|
|
91
|
+
case 7: return 'property';
|
|
92
|
+
case 8: return 'field';
|
|
93
|
+
default: return undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler for retrieving Unity project settings
|
|
5
|
+
*/
|
|
6
|
+
export class GetProjectSettingsToolHandler extends BaseToolHandler {
|
|
7
|
+
constructor(unityConnection) {
|
|
8
|
+
super(
|
|
9
|
+
'get_project_settings',
|
|
10
|
+
'Get project settings by category via include flags (player/graphics/quality/physics/etc.).',
|
|
11
|
+
{
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
includePlayer: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
description: 'Include player settings (company/product name, version, etc.) (default: true).'
|
|
17
|
+
},
|
|
18
|
+
includeGraphics: {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
description: 'Include graphics settings (color space, render pipeline, etc.) (default: false).'
|
|
21
|
+
},
|
|
22
|
+
includeQuality: {
|
|
23
|
+
type: 'boolean',
|
|
24
|
+
description: 'Include quality settings (levels, anti-aliasing, shadows, etc.) (default: false).'
|
|
25
|
+
},
|
|
26
|
+
includePhysics: {
|
|
27
|
+
type: 'boolean',
|
|
28
|
+
description: 'Include 3D physics settings (gravity, solver iterations, etc.) (default: false).'
|
|
29
|
+
},
|
|
30
|
+
includePhysics2D: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Include 2D physics settings (default: false).'
|
|
33
|
+
},
|
|
34
|
+
includeAudio: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Include audio settings (speaker mode, DSP buffer, volume, etc.) (default: false).'
|
|
37
|
+
},
|
|
38
|
+
includeTime: {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: 'Include time settings (fixed timestep, time scale, etc.) (default: false).'
|
|
41
|
+
},
|
|
42
|
+
includeInputManager: {
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
description: 'Include input manager settings (legacy input system) (default: false).'
|
|
45
|
+
},
|
|
46
|
+
includeEditor: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'Include editor settings (Unity Remote, serialization mode, etc.) (default: false).'
|
|
49
|
+
},
|
|
50
|
+
includeBuild: {
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
description: 'Include build settings (scenes in build, build target, etc.) (default: false).'
|
|
53
|
+
},
|
|
54
|
+
includeTags: {
|
|
55
|
+
type: 'boolean',
|
|
56
|
+
description: 'Include tags, layers, and sorting layers (default: false).'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
required: []
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
this.unityConnection = unityConnection;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Validates the input parameters
|
|
68
|
+
* @param {Object} params - The input parameters
|
|
69
|
+
* @throws {Error} If validation fails
|
|
70
|
+
*/
|
|
71
|
+
validate(params) {
|
|
72
|
+
// All parameters are optional booleans with defaults, no special validation needed
|
|
73
|
+
const booleanParams = [
|
|
74
|
+
'includePlayer', 'includeGraphics', 'includeQuality',
|
|
75
|
+
'includePhysics', 'includePhysics2D', 'includeAudio',
|
|
76
|
+
'includeTime', 'includeInputManager', 'includeEditor',
|
|
77
|
+
'includeBuild', 'includeTags'
|
|
78
|
+
];
|
|
79
|
+
|
|
80
|
+
for (const param of booleanParams) {
|
|
81
|
+
if (params[param] !== undefined && typeof params[param] !== 'boolean') {
|
|
82
|
+
throw new Error(`${param} must be a boolean value`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Executes the get project settings operation
|
|
89
|
+
* @param {Object} params - The validated input parameters
|
|
90
|
+
* @returns {Promise<Object>} The project settings
|
|
91
|
+
*/
|
|
92
|
+
async execute(params) {
|
|
93
|
+
// Ensure connection to Unity
|
|
94
|
+
if (!this.unityConnection.isConnected()) {
|
|
95
|
+
await this.unityConnection.connect();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Send command to Unity
|
|
99
|
+
const response = await this.unityConnection.sendCommand('get_project_settings', params);
|
|
100
|
+
|
|
101
|
+
// Handle Unity response
|
|
102
|
+
if (response.error) {
|
|
103
|
+
throw new Error(response.error);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Return the settings object
|
|
107
|
+
return response;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Gets example usage for this tool
|
|
112
|
+
* @returns {Object} Example usage scenarios
|
|
113
|
+
*/
|
|
114
|
+
getExamples() {
|
|
115
|
+
return {
|
|
116
|
+
getBasicSettings: {
|
|
117
|
+
description: 'Get basic player settings only (default)',
|
|
118
|
+
params: {}
|
|
119
|
+
},
|
|
120
|
+
getGraphicsAndQuality: {
|
|
121
|
+
description: 'Get graphics and quality settings',
|
|
122
|
+
params: {
|
|
123
|
+
includeGraphics: true,
|
|
124
|
+
includeQuality: true
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
getPhysicsSettings: {
|
|
128
|
+
description: 'Get all physics-related settings',
|
|
129
|
+
params: {
|
|
130
|
+
includePhysics: true,
|
|
131
|
+
includePhysics2D: true,
|
|
132
|
+
includeTime: true
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
getEditorSettings: {
|
|
136
|
+
description: 'Get editor and build configuration',
|
|
137
|
+
params: {
|
|
138
|
+
includeEditor: true,
|
|
139
|
+
includeBuild: true,
|
|
140
|
+
includeTags: true
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
getAllSettings: {
|
|
144
|
+
description: 'Get all available settings',
|
|
145
|
+
params: {
|
|
146
|
+
includePlayer: true,
|
|
147
|
+
includeGraphics: true,
|
|
148
|
+
includeQuality: true,
|
|
149
|
+
includePhysics: true,
|
|
150
|
+
includePhysics2D: true,
|
|
151
|
+
includeAudio: true,
|
|
152
|
+
includeTime: true,
|
|
153
|
+
includeInputManager: true,
|
|
154
|
+
includeEditor: true,
|
|
155
|
+
includeBuild: true,
|
|
156
|
+
includeTags: true
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler for updating Unity project settings with safety confirmation
|
|
5
|
+
*/
|
|
6
|
+
export class UpdateProjectSettingsToolHandler extends BaseToolHandler {
|
|
7
|
+
constructor(unityConnection) {
|
|
8
|
+
super(
|
|
9
|
+
'update_project_settings',
|
|
10
|
+
'Update project settings by category with a confirmation safety flag.',
|
|
11
|
+
{
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
confirmChanges: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
description: 'Safety flag: must be true to apply changes (prevents accidental edits).'
|
|
17
|
+
},
|
|
18
|
+
player: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
description: 'Player settings (company/product name, bundle version, windowing).',
|
|
21
|
+
properties: {
|
|
22
|
+
companyName: { type: 'string', description: 'Company name' },
|
|
23
|
+
productName: { type: 'string', description: 'Product name' },
|
|
24
|
+
version: { type: 'string', description: 'Bundle version' },
|
|
25
|
+
defaultScreenWidth: { type: 'number', description: 'Default screen width' },
|
|
26
|
+
defaultScreenHeight: { type: 'number', description: 'Default screen height' },
|
|
27
|
+
runInBackground: { type: 'boolean', description: 'Allow running in background' }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
graphics: {
|
|
31
|
+
type: 'object',
|
|
32
|
+
description: 'Graphics settings (color space, render pipeline, etc.).',
|
|
33
|
+
properties: {
|
|
34
|
+
colorSpace: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
enum: ['Gamma', 'Linear'],
|
|
37
|
+
description: 'Color space (requires Unity restart)'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
physics: {
|
|
42
|
+
type: 'object',
|
|
43
|
+
description: '3D physics settings (gravity, solver iterations, thresholds).',
|
|
44
|
+
properties: {
|
|
45
|
+
gravity: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
x: { type: 'number' },
|
|
49
|
+
y: { type: 'number' },
|
|
50
|
+
z: { type: 'number' }
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
defaultSolverIterations: { type: 'number' },
|
|
54
|
+
defaultSolverVelocityIterations: { type: 'number' },
|
|
55
|
+
bounceThreshold: { type: 'number' },
|
|
56
|
+
sleepThreshold: { type: 'number' },
|
|
57
|
+
defaultContactOffset: { type: 'number' }
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
physics2D: {
|
|
61
|
+
type: 'object',
|
|
62
|
+
description: '2D physics settings (gravity, iterations, thresholds).',
|
|
63
|
+
properties: {
|
|
64
|
+
gravity: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: {
|
|
67
|
+
x: { type: 'number' },
|
|
68
|
+
y: { type: 'number' }
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
velocityIterations: { type: 'number' },
|
|
72
|
+
positionIterations: { type: 'number' },
|
|
73
|
+
velocityThreshold: { type: 'number' }
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
audio: {
|
|
77
|
+
type: 'object',
|
|
78
|
+
description: 'Audio settings (global volume).',
|
|
79
|
+
properties: {
|
|
80
|
+
globalVolume: {
|
|
81
|
+
type: 'number',
|
|
82
|
+
minimum: 0,
|
|
83
|
+
maximum: 1,
|
|
84
|
+
description: 'Global volume (0-1)'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
time: {
|
|
89
|
+
type: 'object',
|
|
90
|
+
description: 'Time settings (fixed timestep, time scale).',
|
|
91
|
+
properties: {
|
|
92
|
+
fixedDeltaTime: { type: 'number', description: 'Fixed timestep' },
|
|
93
|
+
timeScale: { type: 'number', minimum: 0, description: 'Time scale (0 = paused)' },
|
|
94
|
+
maximumDeltaTime: { type: 'number', description: 'Maximum allowed timestep' }
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
quality: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
description: 'Quality settings (levels, vSync, AA, shadows).',
|
|
100
|
+
properties: {
|
|
101
|
+
currentLevel: { type: 'string', description: 'Quality level name' },
|
|
102
|
+
vSyncCount: {
|
|
103
|
+
type: 'number',
|
|
104
|
+
minimum: 0,
|
|
105
|
+
maximum: 4,
|
|
106
|
+
description: 'VSync count (0=off, 1=every VBlank, 2=every second VBlank)'
|
|
107
|
+
},
|
|
108
|
+
antiAliasing: {
|
|
109
|
+
type: 'number',
|
|
110
|
+
enum: [0, 2, 4, 8],
|
|
111
|
+
description: 'Anti-aliasing samples'
|
|
112
|
+
},
|
|
113
|
+
shadowDistance: { type: 'number', minimum: 0, description: 'Shadow rendering distance' }
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
required: ['confirmChanges']
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
this.unityConnection = unityConnection;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validates the input parameters
|
|
126
|
+
* @param {Object} params - The input parameters
|
|
127
|
+
* @throws {Error} If validation fails
|
|
128
|
+
*/
|
|
129
|
+
validate(params) {
|
|
130
|
+
// Require explicit confirmation
|
|
131
|
+
if (!params.confirmChanges) {
|
|
132
|
+
throw new Error('confirmChanges must be set to true to update settings. This is a safety measure to prevent accidental changes.');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Check that at least one settings category is provided
|
|
136
|
+
const settingsCategories = ['player', 'graphics', 'physics', 'physics2D', 'audio', 'time', 'quality'];
|
|
137
|
+
const hasSettings = settingsCategories.some(cat => params[cat] !== undefined);
|
|
138
|
+
|
|
139
|
+
if (!hasSettings) {
|
|
140
|
+
throw new Error('At least one settings category must be provided to update');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Validate specific settings
|
|
144
|
+
if (params.audio?.globalVolume !== undefined) {
|
|
145
|
+
const volume = params.audio.globalVolume;
|
|
146
|
+
if (typeof volume !== 'number' || volume < 0 || volume > 1) {
|
|
147
|
+
throw new Error('globalVolume must be a number between 0 and 1');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (params.quality?.vSyncCount !== undefined) {
|
|
152
|
+
const vSync = params.quality.vSyncCount;
|
|
153
|
+
if (!Number.isInteger(vSync) || vSync < 0 || vSync > 4) {
|
|
154
|
+
throw new Error('vSyncCount must be an integer between 0 and 4');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (params.quality?.antiAliasing !== undefined) {
|
|
159
|
+
const aa = params.quality.antiAliasing;
|
|
160
|
+
if (![0, 2, 4, 8].includes(aa)) {
|
|
161
|
+
throw new Error('antiAliasing must be 0, 2, 4, or 8');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (params.graphics?.colorSpace !== undefined) {
|
|
166
|
+
const colorSpace = params.graphics.colorSpace;
|
|
167
|
+
if (!['Gamma', 'Linear'].includes(colorSpace)) {
|
|
168
|
+
throw new Error('colorSpace must be either "Gamma" or "Linear"');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (params.time?.timeScale !== undefined) {
|
|
173
|
+
const timeScale = params.time.timeScale;
|
|
174
|
+
if (typeof timeScale !== 'number' || timeScale < 0) {
|
|
175
|
+
throw new Error('timeScale must be a non-negative number');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Executes the update project settings operation
|
|
182
|
+
* @param {Object} params - The validated input parameters
|
|
183
|
+
* @returns {Promise<Object>} The update results
|
|
184
|
+
*/
|
|
185
|
+
async execute(params) {
|
|
186
|
+
// Ensure connection to Unity
|
|
187
|
+
if (!this.unityConnection.isConnected()) {
|
|
188
|
+
await this.unityConnection.connect();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Send command to Unity
|
|
192
|
+
const response = await this.unityConnection.sendCommand('update_project_settings', params);
|
|
193
|
+
|
|
194
|
+
// Handle Unity response
|
|
195
|
+
if (response.error) {
|
|
196
|
+
// Check for specific error codes
|
|
197
|
+
if (response.code === 'CONFIRMATION_REQUIRED') {
|
|
198
|
+
throw new Error('Settings update requires confirmation. Set confirmChanges to true.');
|
|
199
|
+
}
|
|
200
|
+
throw new Error(response.error);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Return the update results
|
|
204
|
+
return response;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Gets example usage for this tool
|
|
209
|
+
* @returns {Object} Example usage scenarios
|
|
210
|
+
*/
|
|
211
|
+
getExamples() {
|
|
212
|
+
return {
|
|
213
|
+
updatePlayerSettings: {
|
|
214
|
+
description: 'Update player settings like company and product name',
|
|
215
|
+
params: {
|
|
216
|
+
confirmChanges: true,
|
|
217
|
+
player: {
|
|
218
|
+
companyName: 'My Company',
|
|
219
|
+
productName: 'My Game',
|
|
220
|
+
version: '1.0.0'
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
updatePhysicsSettings: {
|
|
225
|
+
description: 'Update physics settings like gravity',
|
|
226
|
+
params: {
|
|
227
|
+
confirmChanges: true,
|
|
228
|
+
physics: {
|
|
229
|
+
gravity: { x: 0, y: -9.81, z: 0 },
|
|
230
|
+
defaultSolverIterations: 10
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
updateQualitySettings: {
|
|
235
|
+
description: 'Update quality settings',
|
|
236
|
+
params: {
|
|
237
|
+
confirmChanges: true,
|
|
238
|
+
quality: {
|
|
239
|
+
vSyncCount: 1,
|
|
240
|
+
antiAliasing: 4,
|
|
241
|
+
shadowDistance: 150
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
updateMultipleCategories: {
|
|
246
|
+
description: 'Update multiple settings categories at once',
|
|
247
|
+
params: {
|
|
248
|
+
confirmChanges: true,
|
|
249
|
+
player: {
|
|
250
|
+
version: '2.0.0'
|
|
251
|
+
},
|
|
252
|
+
audio: {
|
|
253
|
+
globalVolume: 0.8
|
|
254
|
+
},
|
|
255
|
+
time: {
|
|
256
|
+
timeScale: 1.0,
|
|
257
|
+
fixedDeltaTime: 0.02
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
safetyCheckExample: {
|
|
262
|
+
description: 'Example showing safety check (will fail)',
|
|
263
|
+
params: {
|
|
264
|
+
confirmChanges: false, // This will trigger safety check
|
|
265
|
+
player: {
|
|
266
|
+
productName: 'Accidental Change'
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
|
+
|
|
3
|
+
export class GetCommandStatsToolHandler extends BaseToolHandler {
|
|
4
|
+
constructor(unityConnection) {
|
|
5
|
+
super(
|
|
6
|
+
'get_command_stats',
|
|
7
|
+
'Retrieve aggregated counts and recent Unity command types to audit traffic.',
|
|
8
|
+
{
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {},
|
|
11
|
+
required: []
|
|
12
|
+
}
|
|
13
|
+
);
|
|
14
|
+
this.unityConnection = unityConnection;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async execute(params) {
|
|
18
|
+
if (!this.unityConnection.isConnected()) {
|
|
19
|
+
await this.unityConnection.connect();
|
|
20
|
+
}
|
|
21
|
+
const result = await this.unityConnection.sendCommand('get_command_stats', {});
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|