ultimate-unreal-engine-mcp 0.1.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/README.md +729 -0
- package/dist/build/error-parser.js +51 -0
- package/dist/build/fix-suggester.js +84 -0
- package/dist/build/ubt-runner.js +146 -0
- package/dist/cli.js +13 -0
- package/dist/config.js +8 -0
- package/dist/docs/data/ue57-api.js +228 -0
- package/dist/docs/doc-index.js +110 -0
- package/dist/docs/types.js +4 -0
- package/dist/generators/class-generator.js +363 -0
- package/dist/generators/file-modifier.js +276 -0
- package/dist/generators/uht-validator.js +177 -0
- package/dist/index.js +89 -0
- package/dist/parsers/cpp-class-index.js +230 -0
- package/dist/parsers/cpp-parser.js +369 -0
- package/dist/parsers/ini-parser.js +216 -0
- package/dist/parsers/uproject-parser.js +130 -0
- package/dist/plugin-bridge/client.js +217 -0
- package/dist/plugin-bridge/protocol.js +6 -0
- package/dist/plugin-bridge/retry.js +23 -0
- package/dist/setup.js +209 -0
- package/dist/tools/ai-systems/index.js +247 -0
- package/dist/tools/ai-systems/types.js +4 -0
- package/dist/tools/animation/index.js +241 -0
- package/dist/tools/animation/types.js +4 -0
- package/dist/tools/audio/index.js +204 -0
- package/dist/tools/audio/types.js +4 -0
- package/dist/tools/blueprint/index.js +495 -0
- package/dist/tools/blueprint/types.js +4 -0
- package/dist/tools/build/index.js +163 -0
- package/dist/tools/chaos/index.js +230 -0
- package/dist/tools/chaos/types.js +4 -0
- package/dist/tools/collision-physics/index.js +211 -0
- package/dist/tools/config/index.js +288 -0
- package/dist/tools/cpp/index.js +305 -0
- package/dist/tools/docs/index.js +251 -0
- package/dist/tools/editor/index.js +242 -0
- package/dist/tools/gas/index.js +222 -0
- package/dist/tools/gas/types.js +5 -0
- package/dist/tools/import-export/index.js +218 -0
- package/dist/tools/input/index.js +146 -0
- package/dist/tools/known-issues/index.js +88 -0
- package/dist/tools/known-issues/middleware.js +55 -0
- package/dist/tools/known-issues/store.js +125 -0
- package/dist/tools/livelink/index.js +203 -0
- package/dist/tools/livelink/types.js +4 -0
- package/dist/tools/material/index.js +190 -0
- package/dist/tools/motion-design/index.js +251 -0
- package/dist/tools/motion-design/types.js +6 -0
- package/dist/tools/movie-render/index.js +220 -0
- package/dist/tools/networking/index.js +149 -0
- package/dist/tools/pcg/index.js +164 -0
- package/dist/tools/selection/index.js +180 -0
- package/dist/tools/sequencer/index.js +218 -0
- package/dist/tools/validation/index.js +183 -0
- package/dist/tools/validation/types.js +4 -0
- package/dist/tools/viewport/index.js +310 -0
- package/dist/tools/worldpartition/index.js +226 -0
- package/dist/tools/worldpartition/types.js +4 -0
- package/dist/utils/execFileNoThrow.js +40 -0
- package/dist/utils/logger.js +27 -0
- package/dist/utils/path-guard.js +26 -0
- package/package.json +40 -0
- package/unreal-plugin/MCPBridge/MCPBridge.uplugin +29 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/MCPBridgeEditor.Build.cs +68 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.cpp +919 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAICommands.h +23 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.cpp +415 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPActorCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.cpp +653 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAnimationCommands.h +24 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.cpp +290 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAssetCommands.h +17 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.cpp +624 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPAudioCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.cpp +616 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintHandlers.h +25 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.cpp +744 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBlueprintWriteHandlers.h +24 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeEditor.cpp +23 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.cpp +149 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPBridgeSubsystem.h +38 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.cpp +771 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPChaosCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.cpp +749 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPCollisionPhysicsCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.cpp +172 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPEditorStateCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.cpp +715 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPGASCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.cpp +679 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPImportExportCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.cpp +381 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPInputHandlers.h +24 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.cpp +504 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPLiveLinkCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.cpp +511 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMaterialCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.cpp +1110 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMotionDesignCommands.h +28 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.cpp +590 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPMovieRenderCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.cpp +482 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPNetworkingCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.cpp +338 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPPieCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.cpp +677 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSelectionCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.cpp +721 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPSequencerCommands.h +16 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.cpp +368 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPValidationCommands.h +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.cpp +1208 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPViewportCommands.h +29 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.cpp +822 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Private/MCPWorldPartitionCommands.h +23 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeEditor/Public/MCPBridgeEditor.h +14 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/MCPBridgeRuntime.Build.cs +28 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPBridgeRuntime.cpp +22 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPCommandRouter.cpp +118 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Private/MCPTcpServer.cpp +196 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPBridgeRuntime.h +15 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPCommandRouter.h +55 -0
- package/unreal-plugin/MCPBridge/Source/MCPBridgeRuntime/Public/MCPTcpServer.h +59 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// MCPAssetCommands.cpp
|
|
2
|
+
// Implements three MCP command handlers for asset registry queries and level layout.
|
|
3
|
+
//
|
|
4
|
+
// asset.query (EDT-05) -- Query assets by class, path prefix, or tag via IAssetRegistry
|
|
5
|
+
// asset.references (EDT-06) -- Trace hard dependencies and referencers for a package
|
|
6
|
+
// level.layout (EDT-07) -- Return placed actors grouped by sublevel + world partition info
|
|
7
|
+
//
|
|
8
|
+
// All handlers are guaranteed to run on the game thread (FMCPCommandRouter guarantee via AsyncTask).
|
|
9
|
+
// Asset registry queries use pre-indexed data -- no asset loading, no filesystem scan.
|
|
10
|
+
|
|
11
|
+
#include "MCPAssetCommands.h"
|
|
12
|
+
|
|
13
|
+
#include "AssetRegistry/AssetRegistryModule.h"
|
|
14
|
+
#include "AssetRegistry/IAssetRegistry.h"
|
|
15
|
+
#include "AssetRegistry/ARFilter.h"
|
|
16
|
+
#include "Editor.h"
|
|
17
|
+
#include "Engine/World.h"
|
|
18
|
+
#include "Engine/LevelStreaming.h"
|
|
19
|
+
#include "EngineUtils.h"
|
|
20
|
+
#include "GameFramework/Actor.h"
|
|
21
|
+
#include "WorldPartition/WorldPartition.h"
|
|
22
|
+
#include "Serialization/JsonSerializer.h"
|
|
23
|
+
#include "Serialization/JsonWriter.h"
|
|
24
|
+
#include "Dom/JsonObject.h"
|
|
25
|
+
#include "Dom/JsonValue.h"
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// File-scope JSON response helpers (identical pattern to MCPCommandRouter.cpp)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
static FString BuildSuccessResponse(const FString& CorrId, TSharedPtr<FJsonObject> Data)
|
|
32
|
+
{
|
|
33
|
+
TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
|
|
34
|
+
Obj->SetBoolField(TEXT("success"), true);
|
|
35
|
+
Obj->SetStringField(TEXT("correlationId"), CorrId);
|
|
36
|
+
if (Data.IsValid())
|
|
37
|
+
{
|
|
38
|
+
Obj->SetObjectField(TEXT("data"), Data);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
FString Output;
|
|
42
|
+
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&Output);
|
|
43
|
+
FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
|
|
44
|
+
Output += TEXT("\n");
|
|
45
|
+
return Output;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static FString BuildErrorResponse(const FString& CorrId, const FString& Err)
|
|
49
|
+
{
|
|
50
|
+
TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
|
|
51
|
+
Obj->SetBoolField(TEXT("success"), false);
|
|
52
|
+
if (!CorrId.IsEmpty())
|
|
53
|
+
{
|
|
54
|
+
Obj->SetStringField(TEXT("correlationId"), CorrId);
|
|
55
|
+
}
|
|
56
|
+
Obj->SetStringField(TEXT("error"), Err);
|
|
57
|
+
|
|
58
|
+
FString Output;
|
|
59
|
+
TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&Output);
|
|
60
|
+
FJsonSerializer::Serialize(Obj.ToSharedRef(), Writer);
|
|
61
|
+
Output += TEXT("\n");
|
|
62
|
+
return Output;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// RegisterAssetCommands
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
void RegisterAssetCommands(FMCPCommandRouter& Router)
|
|
70
|
+
{
|
|
71
|
+
// -----------------------------------------------------------------------
|
|
72
|
+
// asset.query (EDT-05)
|
|
73
|
+
// Query the Asset Registry for assets matching optional class, path, tag filters.
|
|
74
|
+
// Uses FARFilter + IAssetRegistry::GetAssets — never walks the filesystem.
|
|
75
|
+
// -----------------------------------------------------------------------
|
|
76
|
+
Router.RegisterHandler(TEXT("asset.query"), [](TSharedPtr<FJsonObject> Command, FMCPResponseSender SendResponse)
|
|
77
|
+
{
|
|
78
|
+
const FString CorrId = Command.IsValid() ? Command->GetStringField(TEXT("correlationId")) : TEXT("");
|
|
79
|
+
|
|
80
|
+
// Access the asset registry (pre-indexed, no I/O).
|
|
81
|
+
FAssetRegistryModule& ARModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
82
|
+
IAssetRegistry& AssetRegistry = ARModule.Get();
|
|
83
|
+
|
|
84
|
+
// Read optional payload fields.
|
|
85
|
+
FString AssetClass;
|
|
86
|
+
FString PathPrefix;
|
|
87
|
+
FString TagKey;
|
|
88
|
+
FString TagValue;
|
|
89
|
+
double LimitRaw = 100.0;
|
|
90
|
+
|
|
91
|
+
Command->TryGetStringField(TEXT("asset_class"), AssetClass);
|
|
92
|
+
Command->TryGetStringField(TEXT("path_prefix"), PathPrefix);
|
|
93
|
+
Command->TryGetStringField(TEXT("tag_key"), TagKey);
|
|
94
|
+
Command->TryGetStringField(TEXT("tag_value"), TagValue);
|
|
95
|
+
Command->TryGetNumberField(TEXT("limit"), LimitRaw);
|
|
96
|
+
|
|
97
|
+
const int32 Limit = FMath::Clamp(static_cast<int32>(LimitRaw), 1, 500);
|
|
98
|
+
|
|
99
|
+
// Build filter — all fields optional.
|
|
100
|
+
FARFilter Filter;
|
|
101
|
+
Filter.bRecursivePaths = true;
|
|
102
|
+
|
|
103
|
+
if (!AssetClass.IsEmpty())
|
|
104
|
+
{
|
|
105
|
+
// UE 5.1+ API: ClassPaths preferred over deprecated ClassNames.
|
|
106
|
+
// Add with /Script/Engine prefix for engine classes; also add the
|
|
107
|
+
// deprecated ClassNames as a fallback to catch game/plugin classes.
|
|
108
|
+
Filter.ClassPaths.Add(FTopLevelAssetPath(TEXT("/Script/Engine"), FName(*AssetClass)));
|
|
109
|
+
|
|
110
|
+
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
|
111
|
+
Filter.ClassNames.Add(FName(*AssetClass));
|
|
112
|
+
PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!PathPrefix.IsEmpty())
|
|
116
|
+
{
|
|
117
|
+
Filter.PackagePaths.Add(FName(*PathPrefix));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!TagKey.IsEmpty())
|
|
121
|
+
{
|
|
122
|
+
Filter.TagsAndValues.Add(FName(*TagKey), TagValue);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
TArray<FAssetData> Assets;
|
|
126
|
+
AssetRegistry.GetAssets(Filter, Assets);
|
|
127
|
+
|
|
128
|
+
const int32 Total = Assets.Num();
|
|
129
|
+
const int32 ReturnCount = FMath::Min(Limit, Total);
|
|
130
|
+
|
|
131
|
+
TArray<TSharedPtr<FJsonValue>> AssetArr;
|
|
132
|
+
AssetArr.Reserve(ReturnCount);
|
|
133
|
+
for (int32 i = 0; i < ReturnCount; ++i)
|
|
134
|
+
{
|
|
135
|
+
const FAssetData& AD = Assets[i];
|
|
136
|
+
TSharedPtr<FJsonObject> AObj = MakeShared<FJsonObject>();
|
|
137
|
+
AObj->SetStringField(TEXT("package"), AD.PackageName.ToString());
|
|
138
|
+
AObj->SetStringField(TEXT("name"), AD.AssetName.ToString());
|
|
139
|
+
AObj->SetStringField(TEXT("class"), AD.AssetClassPath.ToString());
|
|
140
|
+
AssetArr.Add(MakeShared<FJsonValueObject>(AObj));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
TSharedPtr<FJsonObject> Data = MakeShared<FJsonObject>();
|
|
144
|
+
Data->SetArrayField(TEXT("assets"), AssetArr);
|
|
145
|
+
Data->SetNumberField(TEXT("count"), ReturnCount);
|
|
146
|
+
Data->SetNumberField(TEXT("total"), Total);
|
|
147
|
+
|
|
148
|
+
SendResponse(BuildSuccessResponse(CorrId, Data));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// -----------------------------------------------------------------------
|
|
152
|
+
// asset.references (EDT-06)
|
|
153
|
+
// Trace both directions of hard asset references for a given package path.
|
|
154
|
+
// Uses pre-indexed IAssetRegistry data — never loads an asset.
|
|
155
|
+
// T-09-08: package_path field is validated before any registry call.
|
|
156
|
+
// -----------------------------------------------------------------------
|
|
157
|
+
Router.RegisterHandler(TEXT("asset.references"), [](TSharedPtr<FJsonObject> Command, FMCPResponseSender SendResponse)
|
|
158
|
+
{
|
|
159
|
+
const FString CorrId = Command.IsValid() ? Command->GetStringField(TEXT("correlationId")) : TEXT("");
|
|
160
|
+
|
|
161
|
+
// Validate required field (T-09-08 mitigation).
|
|
162
|
+
FString PackagePath;
|
|
163
|
+
if (!Command.IsValid() || !Command->TryGetStringField(TEXT("package_path"), PackagePath) || PackagePath.IsEmpty())
|
|
164
|
+
{
|
|
165
|
+
SendResponse(BuildErrorResponse(CorrId, TEXT("missing_package_path")));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
FAssetRegistryModule& ARModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
|
170
|
+
IAssetRegistry& AssetRegistry = ARModule.Get();
|
|
171
|
+
|
|
172
|
+
// Dependencies: what this asset references (outgoing).
|
|
173
|
+
TArray<FName> Dependencies;
|
|
174
|
+
AssetRegistry.GetDependencies(FName(*PackagePath), Dependencies);
|
|
175
|
+
|
|
176
|
+
// Referencers: what references this asset (incoming).
|
|
177
|
+
TArray<FName> Referencers;
|
|
178
|
+
AssetRegistry.GetReferencers(FName(*PackagePath), Referencers);
|
|
179
|
+
|
|
180
|
+
// Convert FName arrays to JSON string arrays.
|
|
181
|
+
TArray<TSharedPtr<FJsonValue>> DepArr;
|
|
182
|
+
DepArr.Reserve(Dependencies.Num());
|
|
183
|
+
for (const FName& Dep : Dependencies)
|
|
184
|
+
{
|
|
185
|
+
DepArr.Add(MakeShared<FJsonValueString>(Dep.ToString()));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
TArray<TSharedPtr<FJsonValue>> RefArr;
|
|
189
|
+
RefArr.Reserve(Referencers.Num());
|
|
190
|
+
for (const FName& Ref : Referencers)
|
|
191
|
+
{
|
|
192
|
+
RefArr.Add(MakeShared<FJsonValueString>(Ref.ToString()));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
TSharedPtr<FJsonObject> Data = MakeShared<FJsonObject>();
|
|
196
|
+
Data->SetStringField(TEXT("package"), PackagePath);
|
|
197
|
+
Data->SetArrayField(TEXT("dependencies"), DepArr);
|
|
198
|
+
Data->SetArrayField(TEXT("referencers"), RefArr);
|
|
199
|
+
Data->SetNumberField(TEXT("dependency_count"), Dependencies.Num());
|
|
200
|
+
Data->SetNumberField(TEXT("referencer_count"), Referencers.Num());
|
|
201
|
+
|
|
202
|
+
SendResponse(BuildSuccessResponse(CorrId, Data));
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// -----------------------------------------------------------------------
|
|
206
|
+
// level.layout (EDT-07)
|
|
207
|
+
// Return placed actors grouped by sublevel, plus streaming level list
|
|
208
|
+
// and world partition flag.
|
|
209
|
+
// T-09-10 mitigation: uses TActorIterator (no asset loading) for actor data.
|
|
210
|
+
// -----------------------------------------------------------------------
|
|
211
|
+
Router.RegisterHandler(TEXT("level.layout"), [](TSharedPtr<FJsonObject> Command, FMCPResponseSender SendResponse)
|
|
212
|
+
{
|
|
213
|
+
const FString CorrId = Command.IsValid() ? Command->GetStringField(TEXT("correlationId")) : TEXT("");
|
|
214
|
+
|
|
215
|
+
if (!GEditor)
|
|
216
|
+
{
|
|
217
|
+
SendResponse(BuildErrorResponse(CorrId, TEXT("no_editor")));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
UWorld* World = GEditor->GetEditorWorldContext().World();
|
|
222
|
+
if (!World)
|
|
223
|
+
{
|
|
224
|
+
SendResponse(BuildErrorResponse(CorrId, TEXT("no_world_open")));
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Collect streaming level info.
|
|
229
|
+
TArray<TSharedPtr<FJsonValue>> StreamingArr;
|
|
230
|
+
for (ULevelStreaming* SL : World->GetStreamingLevels())
|
|
231
|
+
{
|
|
232
|
+
if (!SL)
|
|
233
|
+
{
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
TSharedPtr<FJsonObject> LObj = MakeShared<FJsonObject>();
|
|
237
|
+
LObj->SetStringField(TEXT("package"), SL->GetWorldAssetPackageName());
|
|
238
|
+
LObj->SetBoolField(TEXT("loaded"), SL->IsLevelLoaded());
|
|
239
|
+
StreamingArr.Add(MakeShared<FJsonValueObject>(LObj));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// World partition availability.
|
|
243
|
+
UWorldPartition* WP = World->GetWorldPartition();
|
|
244
|
+
const bool bHasWorldPartition = (WP != nullptr);
|
|
245
|
+
|
|
246
|
+
// Collect placed actors from persistent level and all loaded streaming levels.
|
|
247
|
+
// TActorIterator does not load assets -- safe per T-09-10 mitigation.
|
|
248
|
+
TArray<TSharedPtr<FJsonValue>> ActorArr;
|
|
249
|
+
for (TActorIterator<AActor> It(World, AActor::StaticClass()); It; ++It)
|
|
250
|
+
{
|
|
251
|
+
AActor* A = *It;
|
|
252
|
+
if (!A)
|
|
253
|
+
{
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Skip internal default objects that UE places automatically.
|
|
258
|
+
if (A->GetName().StartsWith(TEXT("Default_")))
|
|
259
|
+
{
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
TSharedPtr<FJsonObject> AObj = MakeShared<FJsonObject>();
|
|
264
|
+
AObj->SetStringField(TEXT("label"), A->GetActorLabel());
|
|
265
|
+
AObj->SetStringField(TEXT("class"), A->GetClass()->GetName());
|
|
266
|
+
AObj->SetStringField(TEXT("id"), A->GetName());
|
|
267
|
+
|
|
268
|
+
ULevel* Level = A->GetLevel();
|
|
269
|
+
AObj->SetStringField(TEXT("sublevel"),
|
|
270
|
+
Level ? Level->GetPackage()->GetName() : TEXT("persistent"));
|
|
271
|
+
|
|
272
|
+
FVector Loc = A->GetActorLocation();
|
|
273
|
+
TSharedPtr<FJsonObject> LocObj = MakeShared<FJsonObject>();
|
|
274
|
+
LocObj->SetNumberField(TEXT("x"), Loc.X);
|
|
275
|
+
LocObj->SetNumberField(TEXT("y"), Loc.Y);
|
|
276
|
+
LocObj->SetNumberField(TEXT("z"), Loc.Z);
|
|
277
|
+
AObj->SetObjectField(TEXT("location"), LocObj);
|
|
278
|
+
|
|
279
|
+
ActorArr.Add(MakeShared<FJsonValueObject>(AObj));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
TSharedPtr<FJsonObject> Data = MakeShared<FJsonObject>();
|
|
283
|
+
Data->SetBoolField(TEXT("world_partition"), bHasWorldPartition);
|
|
284
|
+
Data->SetArrayField(TEXT("streaming_levels"), StreamingArr);
|
|
285
|
+
Data->SetArrayField(TEXT("actors"), ActorArr);
|
|
286
|
+
Data->SetNumberField(TEXT("actor_count"), ActorArr.Num());
|
|
287
|
+
|
|
288
|
+
SendResponse(BuildSuccessResponse(CorrId, Data));
|
|
289
|
+
});
|
|
290
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// MCPAssetCommands.h
|
|
2
|
+
// Declares the registration function for asset registry and level layout MCP command handlers.
|
|
3
|
+
// Handlers: asset.query, asset.references, level.layout
|
|
4
|
+
//
|
|
5
|
+
// Call RegisterAssetCommands(*Router) in MCPBridgeSubsystem::Initialize()
|
|
6
|
+
// BEFORE the TCP server starts accepting connections.
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include "MCPCommandRouter.h"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Register all three asset/level command handlers into the given router.
|
|
14
|
+
* Handlers: asset.query (EDT-05), asset.references (EDT-06), level.layout (EDT-07).
|
|
15
|
+
* Must be called on the game thread before connections arrive.
|
|
16
|
+
*/
|
|
17
|
+
void RegisterAssetCommands(FMCPCommandRouter& Router);
|