blueprint-extractor-mcp 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalogs/example-catalog.js +88 -0
- package/dist/helpers/live-coding.js +4 -0
- package/dist/helpers/subsystem.js +28 -1
- package/dist/project-controller.d.ts +9 -0
- package/dist/project-controller.js +19 -1
- package/dist/register-server-tools.js +2 -2
- package/dist/resources/static-doc-resources.js +2 -1
- package/dist/schemas/tool-inputs.d.ts +1125 -17
- package/dist/schemas/tool-inputs.js +19 -6
- package/dist/tools/project-control.js +39 -23
- package/dist/tools/schema-and-ai-authoring.d.ts +2 -2
- package/dist/tools/schema-and-ai-authoring.js +53 -47
- package/dist/tools/window-ui.js +31 -10
- package/package.json +1 -1
|
@@ -482,4 +482,92 @@ export const exampleCatalog = {
|
|
|
482
482
|
},
|
|
483
483
|
],
|
|
484
484
|
},
|
|
485
|
+
state_tree_bindings: {
|
|
486
|
+
summary: 'Wire task outputs to task inputs using property path bindings. Extract an existing StateTree to discover structIds and property names, then use binding operations to set up data flow.',
|
|
487
|
+
recommended_flow: [
|
|
488
|
+
'extract_asset (discover structIds and property names)',
|
|
489
|
+
'modify_state_tree (add_binding / set_bindings)',
|
|
490
|
+
'extract_asset (verify bindings)',
|
|
491
|
+
'save_assets',
|
|
492
|
+
],
|
|
493
|
+
examples: [
|
|
494
|
+
{
|
|
495
|
+
title: 'add_single_binding',
|
|
496
|
+
tool: 'modify_state_tree',
|
|
497
|
+
arguments: {
|
|
498
|
+
asset_path: '/Game/AI/ST_Character',
|
|
499
|
+
operation: 'add_binding',
|
|
500
|
+
payload: {
|
|
501
|
+
sourcePath: {
|
|
502
|
+
structId: 'EAB9611F4B07D7E2C25A948AFC790A50',
|
|
503
|
+
segments: [{ name: 'SelectedGestureTag' }],
|
|
504
|
+
},
|
|
505
|
+
targetPath: {
|
|
506
|
+
structId: 'F2A3B44C4D08E6A1C25A948AFC790A50',
|
|
507
|
+
segments: [{ name: 'MontageTag' }],
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
context: { description: 'Wire SelectRandomGesture output → PlayMontage input. structIds from extract_asset output.' },
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
title: 'set_all_bindings',
|
|
515
|
+
tool: 'modify_state_tree',
|
|
516
|
+
arguments: {
|
|
517
|
+
asset_path: '/Game/AI/ST_Character',
|
|
518
|
+
operation: 'set_bindings',
|
|
519
|
+
payload: {
|
|
520
|
+
propertyBindings: [
|
|
521
|
+
{
|
|
522
|
+
sourcePath: { segments: [{ name: 'SelectedTag' }] },
|
|
523
|
+
targetPath: { segments: [{ name: 'MontageTag' }] },
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
sourcePath: { segments: [{ name: 'Duration' }] },
|
|
527
|
+
targetPath: { segments: [{ name: 'WaitTime' }] },
|
|
528
|
+
},
|
|
529
|
+
],
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
context: { description: 'Replace all bindings on the StateTree with a new set.' },
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
title: 'remove_binding_by_target',
|
|
536
|
+
tool: 'modify_state_tree',
|
|
537
|
+
arguments: {
|
|
538
|
+
asset_path: '/Game/AI/ST_Character',
|
|
539
|
+
operation: 'remove_binding',
|
|
540
|
+
payload: {
|
|
541
|
+
targetPath: { segments: [{ name: 'MontageTag' }] },
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
context: { description: 'Remove all bindings targeting the MontageTag property.' },
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
title: 'create_with_bindings',
|
|
548
|
+
tool: 'create_state_tree',
|
|
549
|
+
arguments: {
|
|
550
|
+
asset_path: '/Game/AI/ST_NewWithBindings',
|
|
551
|
+
payload: {
|
|
552
|
+
schema: '/Script/GameplayStateTreeModule.StateTreeComponentSchema',
|
|
553
|
+
states: [{
|
|
554
|
+
name: 'Root',
|
|
555
|
+
type: 'State',
|
|
556
|
+
tasks: [
|
|
557
|
+
{ nodeStructType: '/Script/MyMod.STCSelectGesture', name: 'SelectGesture' },
|
|
558
|
+
{ nodeStructType: '/Script/MyMod.STCPlayMontage', name: 'PlayMontage' },
|
|
559
|
+
],
|
|
560
|
+
}],
|
|
561
|
+
bindings: {
|
|
562
|
+
propertyBindings: [{
|
|
563
|
+
sourcePath: { segments: [{ name: 'SelectedGestureTag' }] },
|
|
564
|
+
targetPath: { segments: [{ name: 'MontageTag' }] },
|
|
565
|
+
}],
|
|
566
|
+
},
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
context: { description: 'Create a StateTree with tasks and bindings in a single call.' },
|
|
570
|
+
},
|
|
571
|
+
],
|
|
572
|
+
},
|
|
485
573
|
};
|
|
@@ -36,6 +36,10 @@ export function enrichLiveCodingResult(result, changedPaths = [], lastExternalBu
|
|
|
36
36
|
warnings.push('Live Coding cannot add, remove, or reorder UPROPERTYs or change class layouts. '
|
|
37
37
|
+ 'Use compile_project_code + restart_editor for class layout changes.');
|
|
38
38
|
}
|
|
39
|
+
if (result.noOp && typeof result.compileResult === 'string' && result.compileResult.toLowerCase() === 'nochanges') {
|
|
40
|
+
warnings.push('Live Coding cannot compile newly added source files — it only detects changes to already-compiled .obj files. '
|
|
41
|
+
+ 'Use compile_project_code for new files, then restart_editor to load the new module.');
|
|
42
|
+
}
|
|
39
43
|
const fallbackRecommended = canFallbackFromLiveCoding(result);
|
|
40
44
|
const reason = deriveLiveCodingFallbackReason(result);
|
|
41
45
|
return {
|
|
@@ -47,13 +47,40 @@ export async function callSubsystemJson(client, method, params, options) {
|
|
|
47
47
|
}
|
|
48
48
|
return parsed;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Extracts the best available error message from a UE failure response,
|
|
52
|
+
* checking message, errorMessage, error, diagnostics[], and errors[] fields
|
|
53
|
+
* before falling back to listing the available response keys.
|
|
54
|
+
*/
|
|
55
|
+
function extractFailureMessage(parsed) {
|
|
56
|
+
if (typeof parsed.message === 'string' && parsed.message.length > 0)
|
|
57
|
+
return parsed.message;
|
|
58
|
+
if (typeof parsed.errorMessage === 'string' && parsed.errorMessage.length > 0)
|
|
59
|
+
return parsed.errorMessage;
|
|
60
|
+
if (typeof parsed.error === 'string' && parsed.error.length > 0)
|
|
61
|
+
return parsed.error;
|
|
62
|
+
if (Array.isArray(parsed.diagnostics) && parsed.diagnostics.length > 0) {
|
|
63
|
+
const messages = parsed.diagnostics
|
|
64
|
+
.filter((d) => typeof d === 'object' && d !== null && typeof d.message === 'string')
|
|
65
|
+
.map((d) => d.message);
|
|
66
|
+
if (messages.length > 0)
|
|
67
|
+
return messages.join('; ');
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(parsed.errors) && parsed.errors.length > 0) {
|
|
70
|
+
const first = parsed.errors[0];
|
|
71
|
+
return typeof first === 'string' ? first : JSON.stringify(first);
|
|
72
|
+
}
|
|
73
|
+
const keys = Object.keys(parsed).join(', ');
|
|
74
|
+
return `Operation returned success:false with no diagnostic details. Response keys: [${keys}]`;
|
|
75
|
+
}
|
|
50
76
|
export function jsonToolSuccess(parsed, options = {}) {
|
|
51
77
|
const structuredContent = isRecord(parsed) ? parsed : { data: parsed };
|
|
52
78
|
// Guard: if the UE response indicates failure, route through error path.
|
|
53
79
|
// This prevents tool handlers from accidentally passing error payloads as successes.
|
|
54
80
|
if (isRecord(parsed) && parsed.success === false) {
|
|
81
|
+
const errorText = extractFailureMessage(parsed);
|
|
55
82
|
return {
|
|
56
|
-
content: [{ type: 'text', text: `Error: ${
|
|
83
|
+
content: [{ type: 'text', text: `Error: ${errorText}` }],
|
|
57
84
|
structuredContent,
|
|
58
85
|
isError: true,
|
|
59
86
|
};
|
|
@@ -51,6 +51,7 @@ export interface CompileProjectCodeResult {
|
|
|
51
51
|
stdout?: string;
|
|
52
52
|
stderr?: string;
|
|
53
53
|
uhtCacheFilesDeleted?: string[];
|
|
54
|
+
compilationSucceeded: boolean;
|
|
54
55
|
errorCategory?: BuildErrorCategory;
|
|
55
56
|
errorSummary?: string;
|
|
56
57
|
lockedFiles?: string[];
|
|
@@ -104,6 +105,10 @@ export interface ProjectControllerLike {
|
|
|
104
105
|
readonly liveCodingSupported: boolean;
|
|
105
106
|
classifyChangedPaths(changedPaths: string[], forceRebuild?: boolean): SyncStrategyPlan;
|
|
106
107
|
compileProjectCode(request: CompileProjectCodeRequest): Promise<CompileProjectCodeResult>;
|
|
108
|
+
killEditorProcess(): Promise<{
|
|
109
|
+
killed: boolean;
|
|
110
|
+
error?: string;
|
|
111
|
+
}>;
|
|
107
112
|
launchEditor(request: LaunchEditorRequest): Promise<LaunchEditorResult>;
|
|
108
113
|
waitForEditorRestart(probeConnection: ProbeConnection, options?: {
|
|
109
114
|
disconnectTimeoutMs?: number;
|
|
@@ -131,6 +136,10 @@ export declare class ProjectController implements ProjectControllerLike {
|
|
|
131
136
|
get liveCodingSupported(): boolean;
|
|
132
137
|
classifyChangedPaths(changedPaths: string[], forceRebuild?: boolean): SyncStrategyPlan;
|
|
133
138
|
compileProjectCode(request: CompileProjectCodeRequest): Promise<CompileProjectCodeResult>;
|
|
139
|
+
killEditorProcess(): Promise<{
|
|
140
|
+
killed: boolean;
|
|
141
|
+
error?: string;
|
|
142
|
+
}>;
|
|
134
143
|
launchEditor(request: LaunchEditorRequest): Promise<LaunchEditorResult>;
|
|
135
144
|
waitForEditorRestart(probeConnection: ProbeConnection, options?: {
|
|
136
145
|
disconnectTimeoutMs?: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
1
|
+
import { execSync, spawn } from 'node:child_process';
|
|
2
2
|
import { access, readdir, unlink } from 'node:fs/promises';
|
|
3
3
|
import { constants as fsConstants } from 'node:fs';
|
|
4
4
|
import { dirname, resolve } from 'node:path';
|
|
@@ -358,6 +358,7 @@ export class ProjectController {
|
|
|
358
358
|
},
|
|
359
359
|
durationMs: Date.now() - startedAt,
|
|
360
360
|
exitCode: completed.exitCode,
|
|
361
|
+
compilationSucceeded: completed.exitCode === 0,
|
|
361
362
|
restartRequired: true,
|
|
362
363
|
restartReasons: ['external_build_completed'],
|
|
363
364
|
outputIncluded: includeOutput,
|
|
@@ -380,9 +381,26 @@ export class ProjectController {
|
|
|
380
381
|
if (classification.lockedFiles.length > 0) {
|
|
381
382
|
result.lockedFiles = classification.lockedFiles;
|
|
382
383
|
}
|
|
384
|
+
// Compilation itself succeeded if the failure is only at the link/lock stage
|
|
385
|
+
result.compilationSucceeded = classification.errorCategory === 'locked_file'
|
|
386
|
+
|| classification.errorCategory === 'link';
|
|
383
387
|
}
|
|
384
388
|
return result;
|
|
385
389
|
}
|
|
390
|
+
async killEditorProcess() {
|
|
391
|
+
try {
|
|
392
|
+
if (this.platform === 'win32') {
|
|
393
|
+
execSync('taskkill /F /IM "UnrealEditor.exe"', { timeout: 10000 });
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
execSync('pkill -9 -f UnrealEditor', { timeout: 10000 });
|
|
397
|
+
}
|
|
398
|
+
return { killed: true };
|
|
399
|
+
}
|
|
400
|
+
catch (err) {
|
|
401
|
+
return { killed: false, error: String(err) };
|
|
402
|
+
}
|
|
403
|
+
}
|
|
386
404
|
async launchEditor(request) {
|
|
387
405
|
const engineRoot = request.engineRoot ?? this.env.UE_ENGINE_ROOT;
|
|
388
406
|
const projectPath = request.projectPath ?? this.env.UE_PROJECT_PATH;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { exampleCatalog } from './catalogs/example-catalog.js';
|
|
3
3
|
import { collectRelatedResources, collectToolExampleFamilies as collectToolExampleFamiliesFromCatalog, summarizeOutputSchema, summarizeSchemaFields, } from './helpers/tool-help.js';
|
|
4
|
-
import { AnimMontageMutationOperationSchema, AnimationNotifySelectorSchema, AnimSequenceMutationOperationSchema, BehaviorTreeMutationOperationSchema, BehaviorTreeNodeSelectorSchema, BlackboardKeySchema, BlackboardMutationOperationSchema, BlendParameterSchema, BlendSpaceMutationOperationSchema, BlendSpaceSampleSchema, BlueprintGraphMutationOperationSchema, BlueprintMemberMutationOperationSchema, BuildConfigurationSchema, BuildPlatformSchema, CurveChannelSchema, CurveKeyDeleteSchema, CurveKeyUpsertSchema, CurveTableModeSchema, CurveTableRowSchema, CurveTypeSchema, DataTableRowSchema, ExtractAssetTypeSchema, EnhancedInputValueTypeSchema, FontImportItemSchema, ImportJobListSchema, ImportJobSchema, ImportPayloadSchema, InputMappingSchema, JsonObjectSchema, MaterialConnectionSelectorFieldsSchema, MaterialFontParameterSchema, MaterialFunctionAssetKindSchema, MaterialGraphOperationKindSchema, MaterialGraphOperationSchema, MaterialGraphPayloadSchema, MaterialLayerStackSchema, MaterialNodePositionSchema, MaterialScalarParameterSchema, MaterialStaticSwitchParameterSchema, MaterialTextureParameterSchema, MaterialVectorParameterSchema, MeshImportPayloadSchema, StateTreeEditorNodeSelectorSchema, StateTreeMutationOperationSchema, StateTreeStateSelectorSchema, StateTreeTransitionSelectorSchema,
|
|
4
|
+
import { AnimMontageMutationOperationSchema, AnimationNotifySelectorSchema, AnimSequenceMutationOperationSchema, BehaviorTreeMutationOperationSchema, BehaviorTreeNodeSelectorSchema, BlackboardKeySchema, BlackboardMutationOperationSchema, BlendParameterSchema, BlendSpaceMutationOperationSchema, BlendSpaceSampleSchema, BlueprintGraphMutationOperationSchema, BlueprintMemberMutationOperationSchema, BuildConfigurationSchema, BuildPlatformSchema, CurveChannelSchema, CurveKeyDeleteSchema, CurveKeyUpsertSchema, CurveTableModeSchema, CurveTableRowSchema, CurveTypeSchema, DataTableRowSchema, ExtractAssetTypeSchema, EnhancedInputValueTypeSchema, FontImportItemSchema, ImportJobListSchema, ImportJobSchema, ImportPayloadSchema, InputMappingSchema, JsonObjectSchema, MaterialConnectionSelectorFieldsSchema, MaterialFontParameterSchema, MaterialFunctionAssetKindSchema, MaterialGraphOperationKindSchema, MaterialGraphOperationSchema, MaterialGraphPayloadSchema, MaterialLayerStackSchema, MaterialNodePositionSchema, MaterialScalarParameterSchema, MaterialStaticSwitchParameterSchema, MaterialTextureParameterSchema, MaterialVectorParameterSchema, MeshImportPayloadSchema, StateTreeEditorNodeSelectorSchema, StateTreeMutationOperationSchema, StateTreeStateSelectorSchema, StateTreeTransitionSelectorSchema, StateTreeBindingsObjectSchema, TextureImportPayloadSchema, UserDefinedEnumEntrySchema, UserDefinedEnumMutationOperationSchema, UserDefinedStructFieldSchema, UserDefinedStructMutationOperationSchema, WidgetBlueprintMutationOperationSchema, WidgetNodeSchema, WidgetSelectorFieldsSchema, WindowFontApplicationSchema, } from './schemas/tool-inputs.js';
|
|
5
5
|
import { applyWindowUiChangesResultSchema, AutomationRunListSchema, automationRunSchema, CaptureResultSchema, CascadeResultSchema, CleanupCapturesResultSchema, CompareCaptureResultSchema, CompareMotionCaptureBundleResultSchema, CreateModifyWidgetAnimationResultSchema, ExtractWidgetAnimationResultSchema, ListCapturesResultSchema, motionCaptureModeSchema, MotionCaptureBundleResultSchema, widgetAnimationCheckpointSchema, } from './schemas/tool-results.js';
|
|
6
6
|
import { registerAnimationAuthoringTools } from './tools/animation-authoring.js';
|
|
7
7
|
import { registerAutomationRunTools } from './tools/automation-runs.js';
|
|
@@ -166,7 +166,7 @@ export function registerServerTools({ server, client, projectController, automat
|
|
|
166
166
|
stateTreeStateSelectorSchema: StateTreeStateSelectorSchema,
|
|
167
167
|
stateTreeEditorNodeSelectorSchema: StateTreeEditorNodeSelectorSchema,
|
|
168
168
|
stateTreeTransitionSelectorSchema: StateTreeTransitionSelectorSchema,
|
|
169
|
-
|
|
169
|
+
stateTreeBindingsObjectSchema: StateTreeBindingsObjectSchema,
|
|
170
170
|
});
|
|
171
171
|
registerAnimationAuthoringTools({
|
|
172
172
|
server,
|
|
@@ -64,7 +64,8 @@ export function registerStaticDocResources(server) {
|
|
|
64
64
|
'- UserDefinedEnum: entry selector by name; operations replace_entries, rename_entry, remove_entry, reorder_entries.',
|
|
65
65
|
'- Blackboard: key selector by entryName; operations replace_keys, patch_key, remove_key, set_parent.',
|
|
66
66
|
'- BehaviorTree: node selector by nodePath; operations replace_tree, patch_node, patch_attachment, set_blackboard.',
|
|
67
|
-
'- StateTree: selectors by stateId/statePath, editorNodeId, or transitionId; operations replace_tree, patch_state, patch_editor_node, patch_transition, set_schema.',
|
|
67
|
+
'- StateTree: selectors by stateId/statePath, editorNodeId, or transitionId; operations replace_tree, patch_state, patch_editor_node, patch_transition, set_schema, set_bindings, add_binding, remove_binding. Blueprint-wrapped nodes (StateTreeBlueprintTaskWrapper / StateTreeBlueprintConditionWrapper) require instanceObjectClass for the backing instance to exist at runtime.',
|
|
68
|
+
'- StateTree property bindings wire task/evaluator outputs to task inputs. Use extract_asset to discover structIds and property names. Each binding has sourcePath and targetPath with segments: [{name, arrayIndex?, instanceStruct?}] and optional structId. Operations: set_bindings (replace all), add_binding (append), remove_binding (by targetPath). In replace_tree/create: include as { bindings: { propertyBindings: [...] } }.',
|
|
68
69
|
'- AnimSequence: notify selector by notifyId/notifyGuid with notifyIndex or track metadata as fallback; operations replace_notifies, patch_notify, replace_sync_markers, replace_curve_metadata.',
|
|
69
70
|
'- AnimMontage: notify selector by notifyId/notifyGuid with notifyIndex or track metadata as fallback; operations replace_notifies, patch_notify, replace_sections, replace_slots.',
|
|
70
71
|
'- BlendSpace: sample selector by sampleIndex; operations replace_samples, patch_sample, set_axes.',
|