@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.
- package/README.md +21 -0
- package/bin/unity-mcp-server +1 -1
- package/package.json +1 -1
- package/src/core/codeIndex.js +64 -15
- package/src/core/server.js +3 -34
- package/src/handlers/analysis/AnalyzeSceneContentsToolHandler.js +27 -24
- package/src/handlers/analysis/FindByComponentToolHandler.js +4 -1
- package/src/handlers/analysis/GetAnimatorStateToolHandler.js +5 -5
- package/src/handlers/analysis/GetComponentValuesToolHandler.js +4 -1
- package/src/handlers/analysis/GetGameObjectDetailsToolHandler.js +27 -24
- package/src/handlers/analysis/GetInputActionsStateToolHandler.js +5 -5
- package/src/handlers/analysis/GetObjectReferencesToolHandler.js +4 -1
- package/src/handlers/asset/AssetDatabaseManageToolHandler.js +24 -6
- package/src/handlers/asset/AssetDependencyAnalyzeToolHandler.js +21 -11
- package/src/handlers/asset/AssetImportSettingsManageToolHandler.js +7 -7
- package/src/handlers/asset/AssetMaterialCreateToolHandler.js +78 -81
- package/src/handlers/asset/AssetMaterialModifyToolHandler.js +57 -61
- package/src/handlers/asset/AssetPrefabCreateToolHandler.js +61 -64
- package/src/handlers/asset/AssetPrefabExitModeToolHandler.js +9 -13
- package/src/handlers/asset/AssetPrefabInstantiateToolHandler.js +110 -116
- package/src/handlers/asset/AssetPrefabModifyToolHandler.js +58 -58
- package/src/handlers/asset/AssetPrefabOpenToolHandler.js +7 -5
- package/src/handlers/asset/AssetPrefabSaveToolHandler.js +13 -6
- package/src/handlers/compilation/CompilationGetStateToolHandler.js +4 -3
- package/src/handlers/component/ComponentAddToolHandler.js +2 -2
- package/src/handlers/component/ComponentGetTypesToolHandler.js +17 -21
- package/src/handlers/component/ComponentListToolHandler.js +5 -3
- package/src/handlers/component/ComponentModifyToolHandler.js +3 -3
- package/src/handlers/component/ComponentRemoveToolHandler.js +2 -2
- package/src/handlers/console/ConsoleClearToolHandler.js +36 -46
- package/src/handlers/editor/EditorLayersManageToolHandler.js +7 -6
- package/src/handlers/editor/EditorTagsManageToolHandler.js +20 -11
- package/src/handlers/editor/EditorToolsManageToolHandler.js +2 -2
- package/src/handlers/editor/EditorWindowsManageToolHandler.js +6 -5
- package/src/handlers/gameobject/GameObjectCreateToolHandler.js +62 -66
- package/src/handlers/gameobject/GameObjectDeleteToolHandler.js +9 -9
- package/src/handlers/gameobject/GameObjectFindToolHandler.js +13 -11
- package/src/handlers/gameobject/GameObjectGetHierarchyToolHandler.js +22 -16
- package/src/handlers/input/InputActionAddToolHandler.js +2 -2
- package/src/handlers/input/InputActionMapCreateToolHandler.js +2 -2
- package/src/handlers/input/InputActionMapRemoveToolHandler.js +2 -2
- package/src/handlers/input/InputActionRemoveToolHandler.js +2 -2
- package/src/handlers/input/InputBindingAddToolHandler.js +2 -2
- package/src/handlers/input/InputBindingCompositeCreateToolHandler.js +2 -2
- package/src/handlers/input/InputBindingRemoveAllToolHandler.js +2 -2
- package/src/handlers/input/InputBindingRemoveToolHandler.js +2 -2
- package/src/handlers/input/InputControlSchemesManageToolHandler.js +2 -2
- package/src/handlers/package/PackageManagerToolHandler.js +41 -44
- package/src/handlers/package/RegistryConfigToolHandler.js +28 -7
- package/src/handlers/playmode/PlaymodeGetStateToolHandler.js +12 -16
- package/src/handlers/playmode/PlaymodePauseToolHandler.js +8 -12
- package/src/handlers/playmode/PlaymodeWaitForStateToolHandler.js +6 -3
- package/src/handlers/scene/GetSceneInfoToolHandler.js +11 -11
- package/src/handlers/scene/SceneCreateToolHandler.js +28 -31
- package/src/handlers/scene/SceneListToolHandler.js +21 -24
- package/src/handlers/scene/SceneLoadToolHandler.js +27 -29
- package/src/handlers/scene/SceneSaveToolHandler.js +19 -22
- package/src/handlers/screenshot/ScreenshotCaptureToolHandler.js +88 -66
- package/src/handlers/script/CodeIndexStatusToolHandler.js +4 -3
- package/src/handlers/script/CodeIndexUpdateToolHandler.js +24 -14
- package/src/handlers/script/ScriptCreateClassToolHandler.js +44 -9
- package/src/handlers/script/ScriptPackagesListToolHandler.js +91 -91
- package/src/handlers/script/ScriptRefactorRenameToolHandler.js +80 -71
- package/src/handlers/script/ScriptRemoveSymbolToolHandler.js +21 -7
- package/src/handlers/script/ScriptSearchToolHandler.js +299 -266
- package/src/handlers/script/ScriptSymbolsGetToolHandler.js +88 -79
- package/src/handlers/settings/SettingsGetToolHandler.js +28 -13
- package/src/handlers/settings/SettingsUpdateToolHandler.js +20 -6
- package/src/handlers/ui/UIClickElementToolHandler.js +87 -96
- package/src/handlers/ui/UIFindElementsToolHandler.js +45 -55
- package/src/handlers/ui/UIGetElementStateToolHandler.js +35 -43
- package/src/handlers/ui/UISetElementValueToolHandler.js +42 -49
- package/src/handlers/ui/UISimulateInputToolHandler.js +134 -136
- package/src/handlers/video/VideoCaptureForToolHandler.js +24 -7
- package/src/lsp/LspRpcClient.js +24 -12
- package/src/tools/analysis/analyzeSceneContents.js +85 -85
- package/src/tools/analysis/findByComponent.js +73 -73
- package/src/tools/analysis/getAnimatorState.js +287 -287
- package/src/tools/analysis/getComponentValues.js +161 -161
- package/src/tools/analysis/getGameObjectDetails.js +138 -138
- package/src/tools/analysis/getInputActionsState.js +291 -291
- package/src/tools/analysis/getObjectReferences.js +72 -72
- package/src/tools/input/inputActionsEditor.js +522 -474
- package/src/tools/scene/createScene.js +98 -97
- package/src/tools/scene/getSceneInfo.js +82 -81
- package/src/tools/scene/listScenes.js +70 -69
- package/src/tools/scene/loadScene.js +108 -106
- package/src/tools/scene/saveScene.js +78 -77
- package/src/tools/system/ping.js +9 -12
- package/src/utils/validators.js +2 -2
|
@@ -1,50 +1,42 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
3
|
export class UIGetElementStateToolHandler extends BaseToolHandler {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
includeInteractableInfo: {
|
|
20
|
-
type: 'boolean',
|
|
21
|
-
description: 'Include interaction capabilities (default: true)'
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
required: ['elementPath']
|
|
25
|
-
}
|
|
26
|
-
);
|
|
27
|
-
this.unityConnection = unityConnection;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async execute(params) {
|
|
31
|
-
const {
|
|
32
|
-
elementPath,
|
|
33
|
-
includeChildren = false,
|
|
34
|
-
includeInteractableInfo = true
|
|
35
|
-
} = params;
|
|
36
|
-
|
|
37
|
-
// Ensure connected
|
|
38
|
-
if (!this.unityConnection.isConnected()) {
|
|
39
|
-
await this.unityConnection.connect();
|
|
4
|
+
constructor(unityConnection) {
|
|
5
|
+
super('ui_get_element_state', 'Get detailed state information about UI elements', {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
elementPath: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
description: 'Full hierarchy path to the UI element'
|
|
11
|
+
},
|
|
12
|
+
includeChildren: {
|
|
13
|
+
type: 'boolean',
|
|
14
|
+
description: 'Include child element states (default: false)'
|
|
15
|
+
},
|
|
16
|
+
includeInteractableInfo: {
|
|
17
|
+
type: 'boolean',
|
|
18
|
+
description: 'Include interaction capabilities (default: true)'
|
|
40
19
|
}
|
|
20
|
+
},
|
|
21
|
+
required: ['elementPath']
|
|
22
|
+
});
|
|
23
|
+
this.unityConnection = unityConnection;
|
|
24
|
+
}
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
includeChildren,
|
|
45
|
-
includeInteractableInfo
|
|
46
|
-
});
|
|
26
|
+
async execute(params) {
|
|
27
|
+
const { elementPath, includeChildren = false, includeInteractableInfo = true } = params;
|
|
47
28
|
|
|
48
|
-
|
|
29
|
+
// Ensure connected
|
|
30
|
+
if (!this.unityConnection.isConnected()) {
|
|
31
|
+
await this.unityConnection.connect();
|
|
49
32
|
}
|
|
50
|
-
|
|
33
|
+
|
|
34
|
+
const result = await this.unityConnection.sendCommand('get_ui_element_state', {
|
|
35
|
+
elementPath,
|
|
36
|
+
includeChildren,
|
|
37
|
+
includeInteractableInfo
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,57 +1,50 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
3
|
export class UISetElementValueToolHandler extends BaseToolHandler {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
type: 'boolean',
|
|
28
|
-
description: 'Whether to trigger associated events (default: true)'
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
required: ['elementPath', 'value']
|
|
32
|
-
}
|
|
33
|
-
);
|
|
34
|
-
this.unityConnection = unityConnection;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async execute(params) {
|
|
38
|
-
const {
|
|
39
|
-
elementPath,
|
|
40
|
-
value,
|
|
41
|
-
triggerEvents = true
|
|
42
|
-
} = params;
|
|
43
|
-
|
|
44
|
-
// Ensure connected
|
|
45
|
-
if (!this.unityConnection.isConnected()) {
|
|
46
|
-
await this.unityConnection.connect();
|
|
4
|
+
constructor(unityConnection) {
|
|
5
|
+
super('ui_set_element_value', 'Set values for UI input elements', {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
elementPath: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
description: 'Full hierarchy path to the UI element'
|
|
11
|
+
},
|
|
12
|
+
value: {
|
|
13
|
+
anyOf: [
|
|
14
|
+
{ type: 'string' },
|
|
15
|
+
{ type: 'number' },
|
|
16
|
+
{ type: 'boolean' },
|
|
17
|
+
{ type: 'object' },
|
|
18
|
+
{ type: 'array' },
|
|
19
|
+
{ type: 'null' }
|
|
20
|
+
],
|
|
21
|
+
description:
|
|
22
|
+
'New value to set. Supports string, number, boolean, object, array, or null depending on the UI element type.'
|
|
23
|
+
},
|
|
24
|
+
triggerEvents: {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'Whether to trigger associated events (default: true)'
|
|
47
27
|
}
|
|
28
|
+
},
|
|
29
|
+
required: ['elementPath', 'value']
|
|
30
|
+
});
|
|
31
|
+
this.unityConnection = unityConnection;
|
|
32
|
+
}
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
value,
|
|
52
|
-
triggerEvents
|
|
53
|
-
});
|
|
34
|
+
async execute(params) {
|
|
35
|
+
const { elementPath, value, triggerEvents = true } = params;
|
|
54
36
|
|
|
55
|
-
|
|
37
|
+
// Ensure connected
|
|
38
|
+
if (!this.unityConnection.isConnected()) {
|
|
39
|
+
await this.unityConnection.connect();
|
|
56
40
|
}
|
|
41
|
+
|
|
42
|
+
const result = await this.unityConnection.sendCommand('set_ui_element_value', {
|
|
43
|
+
elementPath,
|
|
44
|
+
value,
|
|
45
|
+
triggerEvents
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
57
50
|
}
|
|
@@ -1,156 +1,154 @@
|
|
|
1
1
|
import { BaseToolHandler } from '../base/BaseToolHandler.js';
|
|
2
2
|
|
|
3
3
|
export class UISimulateInputToolHandler extends BaseToolHandler {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
constructor(unityConnection) {
|
|
5
|
+
super('ui_simulate_input', 'Simulate complex UI interactions and input sequences', {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
// Option 1: Simple single input
|
|
9
|
+
elementPath: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
description: 'Target UI element path (for simple input)'
|
|
12
|
+
},
|
|
13
|
+
inputType: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
enum: ['click', 'doubleclick', 'rightclick', 'hover', 'focus', 'type'],
|
|
16
|
+
description: 'Type of input to simulate (for simple input)'
|
|
17
|
+
},
|
|
18
|
+
inputData: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Data for input (e.g., text to type)'
|
|
21
|
+
},
|
|
22
|
+
// Option 2: Complex sequence
|
|
23
|
+
inputSequence: {
|
|
24
|
+
type: 'array',
|
|
25
|
+
items: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
type: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Action type (click, setvalue)'
|
|
31
|
+
},
|
|
32
|
+
params: {
|
|
9
33
|
type: 'object',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
required: ['type', 'params']
|
|
41
|
-
},
|
|
42
|
-
description: 'Array of input actions to perform (for complex input)'
|
|
43
|
-
},
|
|
44
|
-
waitBetween: {
|
|
45
|
-
type: 'number',
|
|
46
|
-
|
|
47
|
-
minimum: 0,
|
|
48
|
-
maximum: 10000,
|
|
49
|
-
description: 'Delay between actions in milliseconds'
|
|
50
|
-
},
|
|
51
|
-
validateState: {
|
|
52
|
-
type: 'boolean',
|
|
53
|
-
description: 'Validate UI state between actions (default: true)'
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
this.unityConnection = unityConnection;
|
|
34
|
+
description: 'Parameters for the action'
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
required: ['type', 'params']
|
|
38
|
+
},
|
|
39
|
+
description: 'Array of input actions to perform (for complex input)'
|
|
40
|
+
},
|
|
41
|
+
waitBetween: {
|
|
42
|
+
type: 'number',
|
|
43
|
+
|
|
44
|
+
minimum: 0,
|
|
45
|
+
maximum: 10000,
|
|
46
|
+
description: 'Delay between actions in milliseconds'
|
|
47
|
+
},
|
|
48
|
+
validateState: {
|
|
49
|
+
type: 'boolean',
|
|
50
|
+
description: 'Validate UI state between actions (default: true)'
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
this.unityConnection = unityConnection;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
validate(params) {
|
|
58
|
+
// Check if using simple mode or complex mode
|
|
59
|
+
const hasSimpleParams = params.elementPath && params.inputType;
|
|
60
|
+
const hasComplexParams = params.inputSequence;
|
|
61
|
+
|
|
62
|
+
if (!hasSimpleParams && !hasComplexParams) {
|
|
63
|
+
throw new Error('Either (elementPath + inputType) or inputSequence is required');
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const hasComplexParams = params.inputSequence;
|
|
66
|
+
if (hasSimpleParams && hasComplexParams) {
|
|
67
|
+
throw new Error('Cannot use both simple and complex input modes simultaneously');
|
|
68
|
+
}
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
// Validate simple mode
|
|
71
|
+
if (hasSimpleParams) {
|
|
72
|
+
if (!params.elementPath || typeof params.elementPath !== 'string') {
|
|
73
|
+
throw new Error('elementPath must be a non-empty string');
|
|
74
|
+
}
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
76
|
+
const validInputTypes = ['click', 'doubleclick', 'rightclick', 'hover', 'focus', 'type'];
|
|
77
|
+
if (!validInputTypes.includes(params.inputType)) {
|
|
78
|
+
throw new Error(`inputType must be one of: ${validInputTypes.join(', ')}`);
|
|
79
|
+
}
|
|
73
80
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
81
|
+
if (params.inputType === 'type' && !params.inputData) {
|
|
82
|
+
throw new Error('inputData is required when inputType is "type"');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
79
85
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
// Validate complex mode
|
|
87
|
+
if (hasComplexParams) {
|
|
88
|
+
if (!Array.isArray(params.inputSequence)) {
|
|
89
|
+
throw new Error('inputSequence must be an array');
|
|
90
|
+
}
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
92
|
+
if (params.inputSequence.length === 0) {
|
|
93
|
+
throw new Error('inputSequence must contain at least one action');
|
|
94
|
+
}
|
|
89
95
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (params.inputSequence.length === 0) {
|
|
97
|
-
throw new Error('inputSequence must contain at least one action');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Validate each action
|
|
101
|
-
for (const action of params.inputSequence) {
|
|
102
|
-
if (!action.type || !action.params) {
|
|
103
|
-
throw new Error('Each action must have type and params');
|
|
104
|
-
}
|
|
105
|
-
}
|
|
96
|
+
// Validate each action
|
|
97
|
+
for (const action of params.inputSequence) {
|
|
98
|
+
if (!action.type || !action.params) {
|
|
99
|
+
throw new Error('Each action must have type and params');
|
|
106
100
|
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
107
103
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
// Validate waitBetween range
|
|
105
|
+
if (params.waitBetween !== undefined) {
|
|
106
|
+
const wait = params.waitBetween;
|
|
107
|
+
if (typeof wait !== 'number' || wait < 0 || wait > 10000) {
|
|
108
|
+
throw new Error('waitBetween must be between 0 and 10000 milliseconds');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async execute(params) {
|
|
114
|
+
const {
|
|
115
|
+
elementPath,
|
|
116
|
+
inputType,
|
|
117
|
+
inputData,
|
|
118
|
+
inputSequence,
|
|
119
|
+
waitBetween = 100,
|
|
120
|
+
validateState = true
|
|
121
|
+
} = params;
|
|
122
|
+
|
|
123
|
+
// Ensure connected
|
|
124
|
+
if (!this.unityConnection.isConnected()) {
|
|
125
|
+
await this.unityConnection.connect();
|
|
115
126
|
}
|
|
116
127
|
|
|
117
|
-
|
|
118
|
-
const {
|
|
119
|
-
elementPath,
|
|
120
|
-
inputType,
|
|
121
|
-
inputData,
|
|
122
|
-
inputSequence,
|
|
123
|
-
waitBetween = 100,
|
|
124
|
-
validateState = true
|
|
125
|
-
} = params;
|
|
126
|
-
|
|
127
|
-
// Ensure connected
|
|
128
|
-
if (!this.unityConnection.isConnected()) {
|
|
129
|
-
await this.unityConnection.connect();
|
|
130
|
-
}
|
|
128
|
+
let actualInputSequence;
|
|
131
129
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
}];
|
|
143
|
-
} else {
|
|
144
|
-
// Use provided sequence
|
|
145
|
-
actualInputSequence = inputSequence;
|
|
130
|
+
// Handle simple mode - convert to sequence format
|
|
131
|
+
if (elementPath && inputType) {
|
|
132
|
+
actualInputSequence = [
|
|
133
|
+
{
|
|
134
|
+
type: inputType,
|
|
135
|
+
params: {
|
|
136
|
+
elementPath,
|
|
137
|
+
inputData: inputData || null
|
|
138
|
+
}
|
|
146
139
|
}
|
|
140
|
+
];
|
|
141
|
+
} else {
|
|
142
|
+
// Use provided sequence
|
|
143
|
+
actualInputSequence = inputSequence;
|
|
144
|
+
}
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
const result = await this.unityConnection.sendCommand('simulate_ui_input', {
|
|
147
|
+
inputSequence: actualInputSequence,
|
|
148
|
+
waitBetween,
|
|
149
|
+
validateState
|
|
150
|
+
});
|
|
153
151
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -12,12 +12,19 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
|
|
|
12
12
|
{
|
|
13
13
|
type: 'object',
|
|
14
14
|
properties: {
|
|
15
|
-
captureMode: {
|
|
15
|
+
captureMode: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['game'],
|
|
18
|
+
description: 'Capture source. Currently only "game" supported.'
|
|
19
|
+
},
|
|
16
20
|
width: { type: 'number', description: 'Output width (0 = default 1280)' },
|
|
17
21
|
height: { type: 'number', description: 'Output height (0 = default 720)' },
|
|
18
22
|
fps: { type: 'number', description: 'Frames per second (default 30)' },
|
|
19
23
|
durationSec: { type: 'number', description: 'Duration to record in seconds' },
|
|
20
|
-
play: {
|
|
24
|
+
play: {
|
|
25
|
+
type: 'boolean',
|
|
26
|
+
description: 'Enter Play Mode before recording (default true if not already playing)'
|
|
27
|
+
}
|
|
21
28
|
},
|
|
22
29
|
required: ['durationSec']
|
|
23
30
|
}
|
|
@@ -36,13 +43,18 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
|
|
|
36
43
|
try {
|
|
37
44
|
const s0 = await this.unityConnection.sendCommand('playmode_get_state', {});
|
|
38
45
|
needPlay = !(s0 && s0.isPlaying);
|
|
39
|
-
} catch {
|
|
46
|
+
} catch {
|
|
47
|
+
needPlay = true;
|
|
48
|
+
}
|
|
40
49
|
}
|
|
41
50
|
if (needPlay) {
|
|
42
51
|
await this.unityConnection.sendCommand('playmode_play', {});
|
|
43
52
|
for (let i = 0; i < 60; i++) {
|
|
44
53
|
const s = await this.unityConnection.sendCommand('get_editor_state', {});
|
|
45
|
-
if (s && s.isPlaying) {
|
|
54
|
+
if (s && s.isPlaying) {
|
|
55
|
+
enteredPlay = true;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
46
58
|
await sleep(250);
|
|
47
59
|
}
|
|
48
60
|
}
|
|
@@ -62,7 +74,8 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
|
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
// Wait until stopped (status reports isRecording=false)
|
|
65
|
-
const deadline =
|
|
77
|
+
const deadline =
|
|
78
|
+
Date.now() + Math.max(0, Math.floor((params.durationSec || 0) * 1000)) + 1500; // small buffer
|
|
66
79
|
let lastStatus = null;
|
|
67
80
|
while (Date.now() < deadline) {
|
|
68
81
|
lastStatus = await this.unityConnection.sendCommand('video_capture_status', {});
|
|
@@ -88,9 +101,13 @@ export class VideoCaptureForToolHandler extends BaseToolHandler {
|
|
|
88
101
|
return { error: e.message, code: 'CLIENT_ERROR' };
|
|
89
102
|
} finally {
|
|
90
103
|
// If we entered play, attempt to leave play (best-effort)
|
|
91
|
-
try {
|
|
104
|
+
try {
|
|
105
|
+
if (enteredPlay) await this.unityConnection.sendCommand('playmode_stop', {});
|
|
106
|
+
} catch {}
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
function sleep(ms) {
|
|
111
|
+
function sleep(ms) {
|
|
112
|
+
return new Promise(r => setTimeout(r, ms));
|
|
113
|
+
}
|
package/src/lsp/LspRpcClient.js
CHANGED
|
@@ -18,14 +18,18 @@ export class LspRpcClient {
|
|
|
18
18
|
this.proc = await this.mgr.ensureStarted();
|
|
19
19
|
// Attach data handler once per process
|
|
20
20
|
if (this.boundOnData) {
|
|
21
|
-
try {
|
|
21
|
+
try {
|
|
22
|
+
this.proc.stdout.off('data', this.boundOnData);
|
|
23
|
+
} catch {}
|
|
22
24
|
}
|
|
23
|
-
this.boundOnData =
|
|
25
|
+
this.boundOnData = chunk => this.onData(chunk);
|
|
24
26
|
this.proc.stdout.on('data', this.boundOnData);
|
|
25
27
|
// On process close: reject all pending and reset state
|
|
26
28
|
this.proc.on('close', () => {
|
|
27
29
|
for (const [id, p] of Array.from(this.pending.entries())) {
|
|
28
|
-
try {
|
|
30
|
+
try {
|
|
31
|
+
p.reject(new Error('LSP process exited'));
|
|
32
|
+
} catch {}
|
|
29
33
|
this.pending.delete(id);
|
|
30
34
|
}
|
|
31
35
|
this.initialized = false;
|
|
@@ -53,7 +57,9 @@ export class LspRpcClient {
|
|
|
53
57
|
this.pending.get(msg.id).resolve(msg);
|
|
54
58
|
this.pending.delete(msg.id);
|
|
55
59
|
}
|
|
56
|
-
} catch {
|
|
60
|
+
} catch {
|
|
61
|
+
/* ignore */
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
|
|
@@ -72,9 +78,9 @@ export class LspRpcClient {
|
|
|
72
78
|
method: 'initialize',
|
|
73
79
|
params: {
|
|
74
80
|
processId: process.pid,
|
|
75
|
-
rootUri: this.projectRoot ?
|
|
81
|
+
rootUri: this.projectRoot ? 'file://' + String(this.projectRoot).replace(/\\/g, '/') : null,
|
|
76
82
|
capabilities: {},
|
|
77
|
-
workspaceFolders: null
|
|
83
|
+
workspaceFolders: null
|
|
78
84
|
}
|
|
79
85
|
};
|
|
80
86
|
const timeoutMs = Math.max(5000, Math.min(60000, config.lsp?.requestTimeoutMs || 60000));
|
|
@@ -104,12 +110,12 @@ export class LspRpcClient {
|
|
|
104
110
|
if (!resp) return [];
|
|
105
111
|
const payload = resp.result ?? resp;
|
|
106
112
|
const diagnostics = Array.isArray(payload?.diagnostics) ? payload.diagnostics : [];
|
|
107
|
-
return diagnostics.map(
|
|
113
|
+
return diagnostics.map(d => ({
|
|
108
114
|
severity: d?.severity,
|
|
109
115
|
message: d?.message,
|
|
110
116
|
id: d?.id,
|
|
111
117
|
line: d?.line,
|
|
112
|
-
column: d?.column
|
|
118
|
+
column: d?.column
|
|
113
119
|
}));
|
|
114
120
|
}
|
|
115
121
|
|
|
@@ -130,17 +136,23 @@ export class LspRpcClient {
|
|
|
130
136
|
this.writeMessage({ jsonrpc: '2.0', id, method, params });
|
|
131
137
|
return await p;
|
|
132
138
|
} catch (e) {
|
|
133
|
-
const msg = String(e && e.message || e);
|
|
139
|
+
const msg = String((e && e.message) || e);
|
|
134
140
|
const recoverable = /timed out|LSP process exited/i.test(msg);
|
|
135
141
|
if (recoverable && attempt === 1) {
|
|
136
142
|
// Auto-reinit and retry once
|
|
137
|
-
try {
|
|
138
|
-
|
|
143
|
+
try {
|
|
144
|
+
await this.mgr.stop(0);
|
|
145
|
+
} catch {}
|
|
146
|
+
this.proc = null;
|
|
147
|
+
this.initialized = false;
|
|
148
|
+
this.buf = Buffer.alloc(0);
|
|
139
149
|
logger.warn(`[csharp-lsp] recoverable error on ${method}: ${msg}. Retrying once...`);
|
|
140
150
|
return await this.#requestWithRetry(method, params, attempt + 1);
|
|
141
151
|
}
|
|
142
152
|
// Standardize error message
|
|
143
|
-
const hint = recoverable
|
|
153
|
+
const hint = recoverable
|
|
154
|
+
? 'The server was restarted. Try again if the issue persists.'
|
|
155
|
+
: 'Check request parameters or increase lsp.requestTimeoutMs.';
|
|
144
156
|
throw new Error(`[${method}] failed: ${msg}. ${hint}`);
|
|
145
157
|
}
|
|
146
158
|
}
|