@akiojin/unity-mcp-server 2.40.2 → 2.40.3

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.
Files changed (90) hide show
  1. package/README.md +21 -0
  2. package/bin/unity-mcp-server +1 -1
  3. package/package.json +1 -1
  4. package/src/core/codeIndex.js +64 -15
  5. package/src/core/server.js +3 -34
  6. package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +27 -24
  7. package/src/handlers/analysis/FindByComponentToolHandler.js +4 -1
  8. package/src/handlers/analysis/GetAnimatorStateToolHandler.js +5 -5
  9. package/src/handlers/analysis/GetComponentValuesToolHandler.js +4 -1
  10. package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +27 -24
  11. package/src/handlers/analysis/GetInputActionsStateToolHandler.js +5 -5
  12. package/src/handlers/analysis/GetObjectReferencesToolHandler.js +4 -1
  13. package/src/handlers/asset/AssetDatabaseManageToolHandler.js +24 -6
  14. package/src/handlers/asset/AssetDependencyAnalyzeToolHandler.js +21 -11
  15. package/src/handlers/asset/AssetImportSettingsManageToolHandler.js +7 -7
  16. package/src/handlers/asset/AssetMaterialCreateToolHandler.js +78 -81
  17. package/src/handlers/asset/AssetMaterialModifyToolHandler.js +57 -61
  18. package/src/handlers/asset/AssetPrefabCreateToolHandler.js +61 -64
  19. package/src/handlers/asset/AssetPrefabExitModeToolHandler.js +9 -13
  20. package/src/handlers/asset/AssetPrefabInstantiateToolHandler.js +110 -116
  21. package/src/handlers/asset/AssetPrefabModifyToolHandler.js +58 -58
  22. package/src/handlers/asset/AssetPrefabOpenToolHandler.js +7 -5
  23. package/src/handlers/asset/AssetPrefabSaveToolHandler.js +13 -6
  24. package/src/handlers/compilation/CompilationGetStateToolHandler.js +4 -3
  25. package/src/handlers/component/ComponentAddToolHandler.js +2 -2
  26. package/src/handlers/component/ComponentGetTypesToolHandler.js +17 -21
  27. package/src/handlers/component/ComponentListToolHandler.js +5 -3
  28. package/src/handlers/component/ComponentModifyToolHandler.js +3 -3
  29. package/src/handlers/component/ComponentRemoveToolHandler.js +2 -2
  30. package/src/handlers/console/ConsoleClearToolHandler.js +36 -46
  31. package/src/handlers/editor/EditorLayersManageToolHandler.js +7 -6
  32. package/src/handlers/editor/EditorTagsManageToolHandler.js +20 -11
  33. package/src/handlers/editor/EditorToolsManageToolHandler.js +2 -2
  34. package/src/handlers/editor/EditorWindowsManageToolHandler.js +6 -5
  35. package/src/handlers/gameobject/GameObjectCreateToolHandler.js +62 -66
  36. package/src/handlers/gameobject/GameObjectDeleteToolHandler.js +9 -9
  37. package/src/handlers/gameobject/GameObjectFindToolHandler.js +13 -11
  38. package/src/handlers/gameobject/GameObjectGetHierarchyToolHandler.js +22 -16
  39. package/src/handlers/input/InputActionAddToolHandler.js +2 -2
  40. package/src/handlers/input/InputActionMapCreateToolHandler.js +2 -2
  41. package/src/handlers/input/InputActionMapRemoveToolHandler.js +2 -2
  42. package/src/handlers/input/InputActionRemoveToolHandler.js +2 -2
  43. package/src/handlers/input/InputBindingAddToolHandler.js +2 -2
  44. package/src/handlers/input/InputBindingCompositeCreateToolHandler.js +2 -2
  45. package/src/handlers/input/InputBindingRemoveAllToolHandler.js +2 -2
  46. package/src/handlers/input/InputBindingRemoveToolHandler.js +2 -2
  47. package/src/handlers/input/InputControlSchemesManageToolHandler.js +2 -2
  48. package/src/handlers/package/PackageManagerToolHandler.js +41 -44
  49. package/src/handlers/package/RegistryConfigToolHandler.js +28 -7
  50. package/src/handlers/playmode/PlaymodeGetStateToolHandler.js +12 -16
  51. package/src/handlers/playmode/PlaymodePauseToolHandler.js +8 -12
  52. package/src/handlers/playmode/PlaymodeWaitForStateToolHandler.js +6 -3
  53. package/src/handlers/scene/GetSceneInfoToolHandler.js +11 -11
  54. package/src/handlers/scene/SceneCreateToolHandler.js +28 -31
  55. package/src/handlers/scene/SceneListToolHandler.js +21 -24
  56. package/src/handlers/scene/SceneLoadToolHandler.js +27 -29
  57. package/src/handlers/scene/SceneSaveToolHandler.js +19 -22
  58. package/src/handlers/screenshot/ScreenshotCaptureToolHandler.js +88 -66
  59. package/src/handlers/script/CodeIndexStatusToolHandler.js +4 -3
  60. package/src/handlers/script/CodeIndexUpdateToolHandler.js +24 -14
  61. package/src/handlers/script/ScriptCreateClassToolHandler.js +44 -9
  62. package/src/handlers/script/ScriptPackagesListToolHandler.js +91 -91
  63. package/src/handlers/script/ScriptRefactorRenameToolHandler.js +80 -71
  64. package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +21 -7
  65. package/src/handlers/script/ScriptSearchToolHandler.js +299 -266
  66. package/src/handlers/script/ScriptSymbolsGetToolHandler.js +88 -79
  67. package/src/handlers/settings/SettingsGetToolHandler.js +28 -13
  68. package/src/handlers/settings/SettingsUpdateToolHandler.js +20 -6
  69. package/src/handlers/ui/UIClickElementToolHandler.js +87 -96
  70. package/src/handlers/ui/UIFindElementsToolHandler.js +45 -55
  71. package/src/handlers/ui/UIGetElementStateToolHandler.js +35 -43
  72. package/src/handlers/ui/UISetElementValueToolHandler.js +42 -49
  73. package/src/handlers/ui/UISimulateInputToolHandler.js +134 -136
  74. package/src/handlers/video/VideoCaptureForToolHandler.js +24 -7
  75. package/src/lsp/LspRpcClient.js +24 -12
  76. package/src/tools/analysis/analyzeSceneContents.js +85 -85
  77. package/src/tools/analysis/findByComponent.js +73 -73
  78. package/src/tools/analysis/getAnimatorState.js +287 -287
  79. package/src/tools/analysis/getComponentValues.js +161 -161
  80. package/src/tools/analysis/getGameObjectDetails.js +138 -138
  81. package/src/tools/analysis/getInputActionsState.js +291 -291
  82. package/src/tools/analysis/getObjectReferences.js +72 -72
  83. package/src/tools/input/inputActionsEditor.js +522 -474
  84. package/src/tools/scene/createScene.js +98 -97
  85. package/src/tools/scene/getSceneInfo.js +82 -81
  86. package/src/tools/scene/listScenes.js +70 -69
  87. package/src/tools/scene/loadScene.js +108 -106
  88. package/src/tools/scene/saveScene.js +78 -77
  89. package/src/tools/system/ping.js +9 -12
  90. package/src/utils/validators.js +2 -2
@@ -4,93 +4,102 @@ import { BaseToolHandler } from '../base/BaseToolHandler.js';
4
4
  import { ProjectInfoProvider } from '../../core/projectInfo.js';
5
5
 
6
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
- }
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:
17
+ '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/…).'
18
+ }
19
+ },
20
+ required: ['path']
21
+ }
22
+ );
23
+ this.unityConnection = unityConnection;
24
+ this.projectInfo = new ProjectInfoProvider(unityConnection);
25
+ }
25
26
 
26
- validate(params) {
27
- super.validate(params);
27
+ validate(params) {
28
+ super.validate(params);
28
29
 
29
- const { path } = params;
30
+ const { path } = params;
30
31
 
31
- if (!path || path.trim() === '') {
32
- throw new Error('path cannot be empty');
33
- }
32
+ if (!path || path.trim() === '') {
33
+ throw new Error('path cannot be empty');
34
+ }
34
35
 
35
- // Check for .cs extension
36
- if (!path.endsWith('.cs')) {
37
- throw new Error('Only .cs files are supported');
38
- }
36
+ // Check for .cs extension
37
+ if (!path.endsWith('.cs')) {
38
+ throw new Error('Only .cs files are supported');
39
39
  }
40
+ }
40
41
 
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;
42
+ async execute(params) {
43
+ // Normalize to project-relative path (strip repo-root prefixes if provided)
44
+ const rawPath = String(params.path || '').replace(/\\/g, '/');
45
+ const ai = rawPath.indexOf('Assets/');
46
+ const pi = rawPath.indexOf('Packages/');
47
+ const cut = ai >= 0 && pi >= 0 ? Math.min(ai, pi) : ai >= 0 ? ai : pi;
48
+ const relPath = cut >= 0 ? rawPath.substring(cut) : rawPath;
48
49
 
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
- }
50
+ try {
51
+ const info = await this.projectInfo.get();
52
+ if (!relPath.startsWith('Assets/') && !relPath.startsWith('Packages/')) {
53
+ return { error: 'Path must be under Assets/ or Packages/' };
54
+ }
55
+ const abs = path.join(info.projectRoot, relPath);
56
+ const st = await fs.stat(abs).catch(() => null);
57
+ if (!st || !st.isFile()) return { error: 'File not found', path: relPath };
58
+ const { LspRpcClient } = await import('../../lsp/LspRpcClient.js');
59
+ const lsp = new LspRpcClient(info.projectRoot);
60
+ const uri = 'file://' + abs.replace(/\\\\/g, '/');
61
+ const res = await lsp.request('textDocument/documentSymbol', { textDocument: { uri } });
62
+ const docSymbols = res?.result ?? res ?? [];
63
+ const list = [];
64
+ const visit = (s, container) => {
65
+ const start = s.range?.start || s.selectionRange?.start || {};
66
+ list.push({
67
+ name: s.name || '',
68
+ kind: this.mapKind(s.kind),
69
+ container: container || null,
70
+ namespace: null,
71
+ startLine: (start.line ?? 0) + 1,
72
+ startColumn: (start.character ?? 0) + 1,
73
+ endLine: (start.line ?? 0) + 1,
74
+ endColumn: (start.character ?? 0) + 1
75
+ });
76
+ if (Array.isArray(s.children)) for (const c of s.children) visit(c, s.name || container);
77
+ };
78
+ if (Array.isArray(docSymbols)) for (const s of docSymbols) visit(s, null);
79
+ return { success: true, path: relPath, symbols: list };
80
+ } catch (e) {
81
+ return { error: e.message || 'Failed to get symbols' };
82
82
  }
83
+ }
83
84
 
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
- }
85
+ mapKind(k) {
86
+ switch (k) {
87
+ case 5:
88
+ return 'class';
89
+ case 23:
90
+ return 'struct';
91
+ case 11:
92
+ return 'interface';
93
+ case 10:
94
+ return 'enum';
95
+ case 6:
96
+ return 'method';
97
+ case 7:
98
+ return 'property';
99
+ case 8:
100
+ return 'field';
101
+ default:
102
+ return undefined;
95
103
  }
104
+ }
96
105
  }
@@ -13,19 +13,23 @@ export class SettingsGetToolHandler extends BaseToolHandler {
13
13
  properties: {
14
14
  includePlayer: {
15
15
  type: 'boolean',
16
- description: 'Include player settings (company/product name, version, etc.) (default: true).'
16
+ description:
17
+ 'Include player settings (company/product name, version, etc.) (default: true).'
17
18
  },
18
19
  includeGraphics: {
19
20
  type: 'boolean',
20
- description: 'Include graphics settings (color space, render pipeline, etc.) (default: false).'
21
+ description:
22
+ 'Include graphics settings (color space, render pipeline, etc.) (default: false).'
21
23
  },
22
24
  includeQuality: {
23
25
  type: 'boolean',
24
- description: 'Include quality settings (levels, anti-aliasing, shadows, etc.) (default: false).'
26
+ description:
27
+ 'Include quality settings (levels, anti-aliasing, shadows, etc.) (default: false).'
25
28
  },
26
29
  includePhysics: {
27
30
  type: 'boolean',
28
- description: 'Include 3D physics settings (gravity, solver iterations, etc.) (default: false).'
31
+ description:
32
+ 'Include 3D physics settings (gravity, solver iterations, etc.) (default: false).'
29
33
  },
30
34
  includePhysics2D: {
31
35
  type: 'boolean',
@@ -33,11 +37,13 @@ export class SettingsGetToolHandler extends BaseToolHandler {
33
37
  },
34
38
  includeAudio: {
35
39
  type: 'boolean',
36
- description: 'Include audio settings (speaker mode, DSP buffer, volume, etc.) (default: false).'
40
+ description:
41
+ 'Include audio settings (speaker mode, DSP buffer, volume, etc.) (default: false).'
37
42
  },
38
43
  includeTime: {
39
44
  type: 'boolean',
40
- description: 'Include time settings (fixed timestep, time scale, etc.) (default: false).'
45
+ description:
46
+ 'Include time settings (fixed timestep, time scale, etc.) (default: false).'
41
47
  },
42
48
  includeInputManager: {
43
49
  type: 'boolean',
@@ -45,11 +51,13 @@ export class SettingsGetToolHandler extends BaseToolHandler {
45
51
  },
46
52
  includeEditor: {
47
53
  type: 'boolean',
48
- description: 'Include editor settings (Unity Remote, serialization mode, etc.) (default: false).'
54
+ description:
55
+ 'Include editor settings (Unity Remote, serialization mode, etc.) (default: false).'
49
56
  },
50
57
  includeBuild: {
51
58
  type: 'boolean',
52
- description: 'Include build settings (scenes in build, build target, etc.) (default: false).'
59
+ description:
60
+ 'Include build settings (scenes in build, build target, etc.) (default: false).'
53
61
  },
54
62
  includeTags: {
55
63
  type: 'boolean',
@@ -59,7 +67,7 @@ export class SettingsGetToolHandler extends BaseToolHandler {
59
67
  required: []
60
68
  }
61
69
  );
62
-
70
+
63
71
  this.unityConnection = unityConnection;
64
72
  }
65
73
 
@@ -71,10 +79,17 @@ export class SettingsGetToolHandler extends BaseToolHandler {
71
79
  validate(params) {
72
80
  // All parameters are optional booleans with defaults, no special validation needed
73
81
  const booleanParams = [
74
- 'includePlayer', 'includeGraphics', 'includeQuality',
75
- 'includePhysics', 'includePhysics2D', 'includeAudio',
76
- 'includeTime', 'includeInputManager', 'includeEditor',
77
- 'includeBuild', 'includeTags'
82
+ 'includePlayer',
83
+ 'includeGraphics',
84
+ 'includeQuality',
85
+ 'includePhysics',
86
+ 'includePhysics2D',
87
+ 'includeAudio',
88
+ 'includeTime',
89
+ 'includeInputManager',
90
+ 'includeEditor',
91
+ 'includeBuild',
92
+ 'includeTags'
78
93
  ];
79
94
 
80
95
  for (const param of booleanParams) {
@@ -110,14 +110,18 @@ export class SettingsUpdateToolHandler extends BaseToolHandler {
110
110
  enum: [0, 2, 4, 8],
111
111
  description: 'Anti-aliasing samples'
112
112
  },
113
- shadowDistance: { type: 'number', minimum: 0, description: 'Shadow rendering distance' }
113
+ shadowDistance: {
114
+ type: 'number',
115
+ minimum: 0,
116
+ description: 'Shadow rendering distance'
117
+ }
114
118
  }
115
119
  }
116
120
  },
117
121
  required: ['confirmChanges']
118
122
  }
119
123
  );
120
-
124
+
121
125
  this.unityConnection = unityConnection;
122
126
  }
123
127
 
@@ -129,13 +133,23 @@ export class SettingsUpdateToolHandler extends BaseToolHandler {
129
133
  validate(params) {
130
134
  // Require explicit confirmation
131
135
  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.');
136
+ throw new Error(
137
+ 'confirmChanges must be set to true to update settings. This is a safety measure to prevent accidental changes.'
138
+ );
133
139
  }
134
140
 
135
141
  // Check that at least one settings category is provided
136
- const settingsCategories = ['player', 'graphics', 'physics', 'physics2D', 'audio', 'time', 'quality'];
142
+ const settingsCategories = [
143
+ 'player',
144
+ 'graphics',
145
+ 'physics',
146
+ 'physics2D',
147
+ 'audio',
148
+ 'time',
149
+ 'quality'
150
+ ];
137
151
  const hasSettings = settingsCategories.some(cat => params[cat] !== undefined);
138
-
152
+
139
153
  if (!hasSettings) {
140
154
  throw new Error('At least one settings category must be provided to update');
141
155
  }
@@ -261,7 +275,7 @@ export class SettingsUpdateToolHandler extends BaseToolHandler {
261
275
  safetyCheckExample: {
262
276
  description: 'Example showing safety check (will fail)',
263
277
  params: {
264
- confirmChanges: false, // This will trigger safety check
278
+ confirmChanges: false, // This will trigger safety check
265
279
  player: {
266
280
  productName: 'Accidental Change'
267
281
  }
@@ -1,110 +1,101 @@
1
1
  import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
2
 
3
3
  export class UIClickElementToolHandler extends BaseToolHandler {
4
- constructor(unityConnection) {
5
- super(
6
- 'ui_click_element',
7
- 'Simulate clicking on UI elements',
8
- {
9
- type: 'object',
10
- properties: {
11
- elementPath: {
12
- type: 'string',
13
- description: 'Full hierarchy path to the UI element'
14
- },
15
- clickType: {
16
- type: 'string',
17
- enum: ['left', 'right', 'middle'],
18
-
19
- description: 'Type of click (left, right, middle)'
20
- },
21
- holdDuration: {
22
- type: 'number',
23
-
24
- minimum: 0,
25
- maximum: 10000,
26
- description: 'Duration to hold click in milliseconds'
27
- },
28
- position: {
29
- type: 'object',
30
- properties: {
31
- x: {
32
- type: 'number',
33
- minimum: 0,
34
- maximum: 1,
35
- description: 'X position within element (0-1)'
36
- },
37
- y: {
38
- type: 'number',
39
- minimum: 0,
40
- maximum: 1,
41
- description: 'Y position within element (0-1)'
42
- }
43
- },
44
- description: 'Specific position within element to click'
45
- }
46
- },
47
- required: ['elementPath']
48
- }
49
- );
50
- this.unityConnection = unityConnection;
51
- }
4
+ constructor(unityConnection) {
5
+ super('ui_click_element', 'Simulate clicking on UI elements', {
6
+ type: 'object',
7
+ properties: {
8
+ elementPath: {
9
+ type: 'string',
10
+ description: 'Full hierarchy path to the UI element'
11
+ },
12
+ clickType: {
13
+ type: 'string',
14
+ enum: ['left', 'right', 'middle'],
52
15
 
53
- validate(params) {
54
- // Call parent validation for required fields
55
- super.validate(params);
56
-
57
- // Validate clickType enum
58
- if (params.clickType && !['left', 'right', 'middle'].includes(params.clickType)) {
59
- throw new Error('clickType must be one of: left, right, middle');
60
- }
16
+ description: 'Type of click (left, right, middle)'
17
+ },
18
+ holdDuration: {
19
+ type: 'number',
61
20
 
62
- // Validate holdDuration range
63
- if (params.holdDuration !== undefined) {
64
- const duration = params.holdDuration;
65
- if (typeof duration !== 'number' || duration < 0 || duration > 10000) {
66
- throw new Error('holdDuration must be between 0 and 10000 milliseconds');
21
+ minimum: 0,
22
+ maximum: 10000,
23
+ description: 'Duration to hold click in milliseconds'
24
+ },
25
+ position: {
26
+ type: 'object',
27
+ properties: {
28
+ x: {
29
+ type: 'number',
30
+ minimum: 0,
31
+ maximum: 1,
32
+ description: 'X position within element (0-1)'
33
+ },
34
+ y: {
35
+ type: 'number',
36
+ minimum: 0,
37
+ maximum: 1,
38
+ description: 'Y position within element (0-1)'
67
39
  }
40
+ },
41
+ description: 'Specific position within element to click'
68
42
  }
43
+ },
44
+ required: ['elementPath']
45
+ });
46
+ this.unityConnection = unityConnection;
47
+ }
69
48
 
70
- // Validate position object
71
- if (params.position) {
72
- const pos = params.position;
73
- if (pos.x !== undefined && typeof pos.x !== 'number') {
74
- throw new Error('position.x must be a number');
75
- }
76
- if (pos.y !== undefined && typeof pos.y !== 'number') {
77
- throw new Error('position.y must be a number');
78
- }
79
- if (pos.x !== undefined && (pos.x < 0 || pos.x > 1)) {
80
- throw new Error('position.x must be between 0 and 1');
81
- }
82
- if (pos.y !== undefined && (pos.y < 0 || pos.y > 1)) {
83
- throw new Error('position.y must be between 0 and 1');
84
- }
85
- }
49
+ validate(params) {
50
+ // Call parent validation for required fields
51
+ super.validate(params);
52
+
53
+ // Validate clickType enum
54
+ if (params.clickType && !['left', 'right', 'middle'].includes(params.clickType)) {
55
+ throw new Error('clickType must be one of: left, right, middle');
86
56
  }
87
57
 
88
- async execute(params) {
89
- const {
90
- elementPath,
91
- clickType = 'left',
92
- holdDuration = 0,
93
- position
94
- } = params;
58
+ // Validate holdDuration range
59
+ if (params.holdDuration !== undefined) {
60
+ const duration = params.holdDuration;
61
+ if (typeof duration !== 'number' || duration < 0 || duration > 10000) {
62
+ throw new Error('holdDuration must be between 0 and 10000 milliseconds');
63
+ }
64
+ }
95
65
 
96
- // Ensure connected
97
- if (!this.unityConnection.isConnected()) {
98
- await this.unityConnection.connect();
99
- }
66
+ // Validate position object
67
+ if (params.position) {
68
+ const pos = params.position;
69
+ if (pos.x !== undefined && typeof pos.x !== 'number') {
70
+ throw new Error('position.x must be a number');
71
+ }
72
+ if (pos.y !== undefined && typeof pos.y !== 'number') {
73
+ throw new Error('position.y must be a number');
74
+ }
75
+ if (pos.x !== undefined && (pos.x < 0 || pos.x > 1)) {
76
+ throw new Error('position.x must be between 0 and 1');
77
+ }
78
+ if (pos.y !== undefined && (pos.y < 0 || pos.y > 1)) {
79
+ throw new Error('position.y must be between 0 and 1');
80
+ }
81
+ }
82
+ }
100
83
 
101
- const result = await this.unityConnection.sendCommand('click_ui_element', {
102
- elementPath,
103
- clickType,
104
- holdDuration,
105
- position
106
- });
84
+ async execute(params) {
85
+ const { elementPath, clickType = 'left', holdDuration = 0, position } = params;
107
86
 
108
- return result;
87
+ // Ensure connected
88
+ if (!this.unityConnection.isConnected()) {
89
+ await this.unityConnection.connect();
109
90
  }
110
- }
91
+
92
+ const result = await this.unityConnection.sendCommand('click_ui_element', {
93
+ elementPath,
94
+ clickType,
95
+ holdDuration,
96
+ position
97
+ });
98
+
99
+ return result;
100
+ }
101
+ }
@@ -1,63 +1,53 @@
1
1
  import { BaseToolHandler } from '../base/BaseToolHandler.js';
2
2
 
3
3
  export class UIFindElementsToolHandler extends BaseToolHandler {
4
- constructor(unityConnection) {
5
- super(
6
- 'ui_find_elements',
7
- 'Find UI elements by component type, tag, or name pattern.',
8
- {
9
- type: 'object',
10
- properties: {
11
- elementType: {
12
- type: 'string',
13
- description: 'UI component type (e.g., Button, Toggle, Slider).'
14
- },
15
- tagFilter: {
16
- type: 'string',
17
- description: 'Filter by GameObject tag.'
18
- },
19
- namePattern: {
20
- type: 'string',
21
- description: 'Search by name substring or regex.'
22
- },
23
- includeInactive: {
24
- type: 'boolean',
25
- description: 'If true, include inactive UI elements.'
26
- },
27
- canvasFilter: {
28
- type: 'string',
29
- description: 'Filter by parent Canvas name.'
30
- }
31
- },
32
- required: []
33
- }
34
- );
35
- this.unityConnection = unityConnection;
36
- }
37
-
38
- async execute(params = {}) {
39
- const {
40
- elementType,
41
- tagFilter,
42
- namePattern,
43
- includeInactive = false,
44
- canvasFilter
45
- } = params;
46
-
47
- // Ensure connected
48
- if (!this.unityConnection.isConnected()) {
49
- await this.unityConnection.connect();
4
+ constructor(unityConnection) {
5
+ super('ui_find_elements', 'Find UI elements by component type, tag, or name pattern.', {
6
+ type: 'object',
7
+ properties: {
8
+ elementType: {
9
+ type: 'string',
10
+ description: 'UI component type (e.g., Button, Toggle, Slider).'
11
+ },
12
+ tagFilter: {
13
+ type: 'string',
14
+ description: 'Filter by GameObject tag.'
15
+ },
16
+ namePattern: {
17
+ type: 'string',
18
+ description: 'Search by name substring or regex.'
19
+ },
20
+ includeInactive: {
21
+ type: 'boolean',
22
+ description: 'If true, include inactive UI elements.'
23
+ },
24
+ canvasFilter: {
25
+ type: 'string',
26
+ description: 'Filter by parent Canvas name.'
50
27
  }
28
+ },
29
+ required: []
30
+ });
31
+ this.unityConnection = unityConnection;
32
+ }
51
33
 
52
- const result = await this.unityConnection.sendCommand('find_ui_elements', {
53
- elementType,
54
- tagFilter,
55
- namePattern,
56
- includeInactive,
57
- canvasFilter
58
- });
34
+ async execute(params = {}) {
35
+ const { elementType, tagFilter, namePattern, includeInactive = false, canvasFilter } = params;
59
36
 
60
- // Return the result for the BaseToolHandler to format
61
- return result;
37
+ // Ensure connected
38
+ if (!this.unityConnection.isConnected()) {
39
+ await this.unityConnection.connect();
62
40
  }
41
+
42
+ const result = await this.unityConnection.sendCommand('find_ui_elements', {
43
+ elementType,
44
+ tagFilter,
45
+ namePattern,
46
+ includeInactive,
47
+ canvasFilter
48
+ });
49
+
50
+ // Return the result for the BaseToolHandler to format
51
+ return result;
52
+ }
63
53
  }