ue-mcp 1.2.1 → 1.2.2
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/context-cli.js +16 -16
- package/dist/engine-observer.js +68 -68
- package/dist/flow/guard.d.ts +26 -37
- package/dist/flow/guard.js +40 -25
- package/dist/flow/guard.js.map +1 -1
- package/dist/flow/guarded-bridge.d.ts +0 -10
- package/dist/flow/guarded-bridge.js +18 -23
- package/dist/flow/guarded-bridge.js.map +1 -1
- package/dist/flow/schema.d.ts +276 -16
- package/dist/flow/task-guards.d.ts +1 -1
- package/dist/flow/task-guards.js +44 -68
- package/dist/flow/task-guards.js.map +1 -1
- package/dist/instructions.js +130 -130
- package/dist/plugin-cli.js +299 -299
- package/dist/tool-counts.json +2 -2
- package/package.json +2 -2
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.cpp +76 -76
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/EngineStatusHooks.h +27 -27
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.cpp +128 -128
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/HandlerRegistry.h +63 -63
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AnimationHandlers_ControlRig.cpp +230 -230
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/AssetHandlers_Struct.cpp +323 -323
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/BlueprintHandlers_Internal.h +20 -20
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/ChooserHandlers_Nested.cpp +537 -537
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/DemoHandlers.h +77 -77
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/EditorHandlers_Build.cpp +353 -353
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/FoliageHandlers.h +18 -18
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GameplayHandlers_InputRuntime.cpp +246 -246
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.cpp +597 -597
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/GasHandlers.h +51 -51
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers.cpp +878 -878
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/LandscapeHandlers_Sculpt.cpp +449 -449
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Function.cpp +275 -275
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/MaterialHandlers_Graph.cpp +551 -551
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.cpp +531 -531
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/NetworkingHandlers.h +28 -28
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/PhysicsHandlers.cpp +677 -677
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.cpp +822 -822
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SequencerHandlers.h +22 -22
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.cpp +218 -218
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/SplineHandlers.h +17 -17
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.cpp +46 -46
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.h +23 -23
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/MCPExternalRegistry.cpp +83 -83
- package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Public/UE_MCP_BridgeModule.h +14 -14
- package/plugin/ue_mcp_bridge/Source/UE_MCP_BridgeStatus/Private/UE_MCP_BridgeStatusModule.cpp +37 -37
- package/dist/manifest-signature.d.ts +0 -1
- package/dist/manifest-signature.js +0 -53
- package/dist/manifest-signature.js.map +0 -1
- package/dist/pie/schema.d.ts +0 -791
- package/dist/pie/schema.js +0 -151
- package/dist/pie/schema.js.map +0 -1
- package/dist/watch-cli.js.map +0 -1
- /package/plugin/ue_mcp_bridge/{ue_mcp_bridge.uplugin → UE_MCP_Bridge.uplugin} +0 -0
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "CoreMinimal.h"
|
|
4
|
-
#include "Dom/JsonValue.h"
|
|
5
|
-
#include "Dom/JsonObject.h"
|
|
6
|
-
|
|
7
|
-
class FSequencerHandlers
|
|
8
|
-
{
|
|
9
|
-
public:
|
|
10
|
-
// Register all sequencer handlers
|
|
11
|
-
static void RegisterHandlers(class FMCPHandlerRegistry& Registry);
|
|
12
|
-
|
|
13
|
-
private:
|
|
14
|
-
// Handler implementations
|
|
15
|
-
static TSharedPtr<FJsonValue> CreateLevelSequence(const TSharedPtr<FJsonObject>& Params);
|
|
16
|
-
static TSharedPtr<FJsonValue> ReadSequenceInfo(const TSharedPtr<FJsonObject>& Params);
|
|
17
|
-
static TSharedPtr<FJsonValue> AddTrack(const TSharedPtr<FJsonObject>& Params);
|
|
18
|
-
static TSharedPtr<FJsonValue> SequenceControl(const TSharedPtr<FJsonObject>& Params);
|
|
19
|
-
static TSharedPtr<FJsonValue> SetPlaybackRange(const TSharedPtr<FJsonObject>& Params);
|
|
20
|
-
static TSharedPtr<FJsonValue> AddSection(const TSharedPtr<FJsonObject>& Params);
|
|
21
|
-
static TSharedPtr<FJsonValue> SetKeyframes(const TSharedPtr<FJsonObject>& Params);
|
|
22
|
-
};
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "Dom/JsonValue.h"
|
|
5
|
+
#include "Dom/JsonObject.h"
|
|
6
|
+
|
|
7
|
+
class FSequencerHandlers
|
|
8
|
+
{
|
|
9
|
+
public:
|
|
10
|
+
// Register all sequencer handlers
|
|
11
|
+
static void RegisterHandlers(class FMCPHandlerRegistry& Registry);
|
|
12
|
+
|
|
13
|
+
private:
|
|
14
|
+
// Handler implementations
|
|
15
|
+
static TSharedPtr<FJsonValue> CreateLevelSequence(const TSharedPtr<FJsonObject>& Params);
|
|
16
|
+
static TSharedPtr<FJsonValue> ReadSequenceInfo(const TSharedPtr<FJsonObject>& Params);
|
|
17
|
+
static TSharedPtr<FJsonValue> AddTrack(const TSharedPtr<FJsonObject>& Params);
|
|
18
|
+
static TSharedPtr<FJsonValue> SequenceControl(const TSharedPtr<FJsonObject>& Params);
|
|
19
|
+
static TSharedPtr<FJsonValue> SetPlaybackRange(const TSharedPtr<FJsonObject>& Params);
|
|
20
|
+
static TSharedPtr<FJsonValue> AddSection(const TSharedPtr<FJsonObject>& Params);
|
|
21
|
+
static TSharedPtr<FJsonValue> SetKeyframes(const TSharedPtr<FJsonObject>& Params);
|
|
22
|
+
};
|
|
@@ -1,218 +1,218 @@
|
|
|
1
|
-
#include "SplineHandlers.h"
|
|
2
|
-
#include "HandlerRegistry.h"
|
|
3
|
-
#include "HandlerUtils.h"
|
|
4
|
-
#include "Components/SplineComponent.h"
|
|
5
|
-
#include "Engine/World.h"
|
|
6
|
-
#include "Editor.h"
|
|
7
|
-
#include "Editor/EditorEngine.h"
|
|
8
|
-
#include "GameFramework/Actor.h"
|
|
9
|
-
#include "EngineUtils.h"
|
|
10
|
-
#include "Dom/JsonObject.h"
|
|
11
|
-
#include "Dom/JsonValue.h"
|
|
12
|
-
|
|
13
|
-
void FSplineHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
14
|
-
{
|
|
15
|
-
Registry.RegisterHandler(TEXT("get_spline_info"), &ReadSpline);
|
|
16
|
-
Registry.RegisterHandler(TEXT("set_spline_points"), &SetSplinePoints);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
TSharedPtr<FJsonValue> FSplineHandlers::ReadSpline(const TSharedPtr<FJsonObject>& Params)
|
|
20
|
-
{
|
|
21
|
-
FString ActorLabel;
|
|
22
|
-
if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
|
|
23
|
-
|
|
24
|
-
// #553: support editor or PIE world so runtime spline state is readable.
|
|
25
|
-
const FString WorldScope = OptionalString(Params, TEXT("world"), TEXT("editor"));
|
|
26
|
-
UWorld* World = ResolveWorldFromParams(Params, *WorldScope);
|
|
27
|
-
if (!World) return MCPError(TEXT("World not available"));
|
|
28
|
-
|
|
29
|
-
AActor* Actor = FindActorByLabelOrName(World, ActorLabel);
|
|
30
|
-
if (!Actor)
|
|
31
|
-
{
|
|
32
|
-
return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// #553: optional componentName to target a specific (custom) spline component
|
|
36
|
-
// when an actor has more than one. Custom spline subclasses derive from
|
|
37
|
-
// USplineComponent, so FindComponentByClass still resolves them.
|
|
38
|
-
USplineComponent* SplineComp = nullptr;
|
|
39
|
-
const FString ComponentName = OptionalString(Params, TEXT("componentName"));
|
|
40
|
-
if (!ComponentName.IsEmpty())
|
|
41
|
-
{
|
|
42
|
-
TArray<USplineComponent*> Comps;
|
|
43
|
-
Actor->GetComponents<USplineComponent>(Comps);
|
|
44
|
-
for (USplineComponent* C : Comps)
|
|
45
|
-
{
|
|
46
|
-
if (C && C->GetName() == ComponentName) { SplineComp = C; break; }
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
else
|
|
50
|
-
{
|
|
51
|
-
SplineComp = Actor->FindComponentByClass<USplineComponent>();
|
|
52
|
-
}
|
|
53
|
-
if (!SplineComp)
|
|
54
|
-
{
|
|
55
|
-
return MCPError(FString::Printf(TEXT("Actor '%s' has no matching SplineComponent"), *ActorLabel));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
auto Result = MCPSuccess();
|
|
59
|
-
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
60
|
-
Result->SetStringField(TEXT("componentName"), SplineComp->GetName());
|
|
61
|
-
Result->SetStringField(TEXT("componentClass"), SplineComp->GetClass()->GetName());
|
|
62
|
-
Result->SetNumberField(TEXT("splinePointCount"), SplineComp->GetNumberOfSplinePoints());
|
|
63
|
-
Result->SetBoolField(TEXT("closedLoop"), SplineComp->IsClosedLoop());
|
|
64
|
-
Result->SetNumberField(TEXT("splineLength"), SplineComp->GetSplineLength());
|
|
65
|
-
|
|
66
|
-
// #555: project a world point onto the spline. Returns the closest location,
|
|
67
|
-
// the input key, distance along the spline, and the perpendicular distance.
|
|
68
|
-
if (Params->HasField(TEXT("projectPoint")))
|
|
69
|
-
{
|
|
70
|
-
const FVector P = OptionalVec3(Params, TEXT("projectPoint"), FVector::ZeroVector);
|
|
71
|
-
const FVector Closest = SplineComp->FindLocationClosestToWorldLocation(P, ESplineCoordinateSpace::World);
|
|
72
|
-
const float InputKey = SplineComp->FindInputKeyClosestToWorldLocation(P);
|
|
73
|
-
const float DistAlong = SplineComp->GetDistanceAlongSplineAtSplineInputKey(InputKey);
|
|
74
|
-
TSharedPtr<FJsonObject> Proj = MakeShared<FJsonObject>();
|
|
75
|
-
Proj->SetObjectField(TEXT("closestLocation"), MCPVec3ToJsonObject(Closest));
|
|
76
|
-
Proj->SetNumberField(TEXT("inputKey"), InputKey);
|
|
77
|
-
Proj->SetNumberField(TEXT("distanceAlongSpline"), DistAlong);
|
|
78
|
-
Proj->SetNumberField(TEXT("distanceToSpline"), FVector::Dist(P, Closest));
|
|
79
|
-
Proj->SetObjectField(TEXT("tangent"), MCPVec3ToJsonObject(SplineComp->GetTangentAtDistanceAlongSpline(DistAlong, ESplineCoordinateSpace::World)));
|
|
80
|
-
Result->SetObjectField(TEXT("projection"), Proj);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Return all control points with world-space locations
|
|
84
|
-
TArray<TSharedPtr<FJsonValue>> PointsArray;
|
|
85
|
-
for (int32 i = 0; i < SplineComp->GetNumberOfSplinePoints(); ++i)
|
|
86
|
-
{
|
|
87
|
-
TSharedPtr<FJsonObject> PointObj = MakeShared<FJsonObject>();
|
|
88
|
-
PointObj->SetNumberField(TEXT("index"), i);
|
|
89
|
-
|
|
90
|
-
FVector WorldPos = SplineComp->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
91
|
-
TSharedPtr<FJsonObject> LocationObj = MakeShared<FJsonObject>();
|
|
92
|
-
LocationObj->SetNumberField(TEXT("x"), WorldPos.X);
|
|
93
|
-
LocationObj->SetNumberField(TEXT("y"), WorldPos.Y);
|
|
94
|
-
LocationObj->SetNumberField(TEXT("z"), WorldPos.Z);
|
|
95
|
-
PointObj->SetObjectField(TEXT("worldLocation"), LocationObj);
|
|
96
|
-
|
|
97
|
-
FVector LocalPos = SplineComp->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::Local);
|
|
98
|
-
TSharedPtr<FJsonObject> LocalObj = MakeShared<FJsonObject>();
|
|
99
|
-
LocalObj->SetNumberField(TEXT("x"), LocalPos.X);
|
|
100
|
-
LocalObj->SetNumberField(TEXT("y"), LocalPos.Y);
|
|
101
|
-
LocalObj->SetNumberField(TEXT("z"), LocalPos.Z);
|
|
102
|
-
PointObj->SetObjectField(TEXT("localLocation"), LocalObj);
|
|
103
|
-
|
|
104
|
-
FVector ArriveTangent = SplineComp->GetArriveTangentAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
105
|
-
TSharedPtr<FJsonObject> ArriveObj = MakeShared<FJsonObject>();
|
|
106
|
-
ArriveObj->SetNumberField(TEXT("x"), ArriveTangent.X);
|
|
107
|
-
ArriveObj->SetNumberField(TEXT("y"), ArriveTangent.Y);
|
|
108
|
-
ArriveObj->SetNumberField(TEXT("z"), ArriveTangent.Z);
|
|
109
|
-
PointObj->SetObjectField(TEXT("arriveTangent"), ArriveObj);
|
|
110
|
-
|
|
111
|
-
FVector LeaveTangent = SplineComp->GetLeaveTangentAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
112
|
-
TSharedPtr<FJsonObject> LeaveObj = MakeShared<FJsonObject>();
|
|
113
|
-
LeaveObj->SetNumberField(TEXT("x"), LeaveTangent.X);
|
|
114
|
-
LeaveObj->SetNumberField(TEXT("y"), LeaveTangent.Y);
|
|
115
|
-
LeaveObj->SetNumberField(TEXT("z"), LeaveTangent.Z);
|
|
116
|
-
PointObj->SetObjectField(TEXT("leaveTangent"), LeaveObj);
|
|
117
|
-
|
|
118
|
-
// Point type
|
|
119
|
-
ESplinePointType::Type PointType = SplineComp->GetSplinePointType(i);
|
|
120
|
-
FString PointTypeStr;
|
|
121
|
-
switch (PointType)
|
|
122
|
-
{
|
|
123
|
-
case ESplinePointType::Linear: PointTypeStr = TEXT("Linear"); break;
|
|
124
|
-
case ESplinePointType::Curve: PointTypeStr = TEXT("Curve"); break;
|
|
125
|
-
case ESplinePointType::Constant: PointTypeStr = TEXT("Constant"); break;
|
|
126
|
-
case ESplinePointType::CurveClamped: PointTypeStr = TEXT("CurveClamped"); break;
|
|
127
|
-
case ESplinePointType::CurveCustomTangent: PointTypeStr = TEXT("CurveCustomTangent"); break;
|
|
128
|
-
default: PointTypeStr = TEXT("Unknown"); break;
|
|
129
|
-
}
|
|
130
|
-
PointObj->SetStringField(TEXT("pointType"), PointTypeStr);
|
|
131
|
-
|
|
132
|
-
PointsArray.Add(MakeShared<FJsonValueObject>(PointObj));
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
Result->SetArrayField(TEXT("points"), PointsArray);
|
|
136
|
-
|
|
137
|
-
return MCPResult(Result);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
TSharedPtr<FJsonValue> FSplineHandlers::SetSplinePoints(const TSharedPtr<FJsonObject>& Params)
|
|
141
|
-
{
|
|
142
|
-
FString ActorLabel;
|
|
143
|
-
if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
|
|
144
|
-
|
|
145
|
-
const TArray<TSharedPtr<FJsonValue>>* PointsArray = nullptr;
|
|
146
|
-
if (!Params->TryGetArrayField(TEXT("points"), PointsArray))
|
|
147
|
-
{
|
|
148
|
-
return MCPError(TEXT("Missing 'points' parameter (array of {x, y, z} objects)"));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
REQUIRE_EDITOR_WORLD(World);
|
|
152
|
-
|
|
153
|
-
AActor* Actor = FindActorByLabel(World, ActorLabel);
|
|
154
|
-
if (!Actor)
|
|
155
|
-
{
|
|
156
|
-
return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Find spline component
|
|
160
|
-
USplineComponent* SplineComp = Actor->FindComponentByClass<USplineComponent>();
|
|
161
|
-
if (!SplineComp)
|
|
162
|
-
{
|
|
163
|
-
return MCPError(FString::Printf(TEXT("Actor '%s' does not have a SplineComponent"), *ActorLabel));
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Capture previous spline points for rollback
|
|
167
|
-
TArray<TSharedPtr<FJsonValue>> PrevPoints;
|
|
168
|
-
for (int32 i = 0; i < SplineComp->GetNumberOfSplinePoints(); ++i)
|
|
169
|
-
{
|
|
170
|
-
FVector P = SplineComp->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
171
|
-
TSharedPtr<FJsonObject> PObj = MakeShared<FJsonObject>();
|
|
172
|
-
PObj->SetNumberField(TEXT("x"), P.X);
|
|
173
|
-
PObj->SetNumberField(TEXT("y"), P.Y);
|
|
174
|
-
PObj->SetNumberField(TEXT("z"), P.Z);
|
|
175
|
-
PrevPoints.Add(MakeShared<FJsonValueObject>(PObj));
|
|
176
|
-
}
|
|
177
|
-
const bool bPrevClosedLoop = SplineComp->IsClosedLoop();
|
|
178
|
-
|
|
179
|
-
// Clear existing points and add new ones
|
|
180
|
-
SplineComp->ClearSplinePoints(false);
|
|
181
|
-
|
|
182
|
-
for (int32 i = 0; i < PointsArray->Num(); ++i)
|
|
183
|
-
{
|
|
184
|
-
const TSharedPtr<FJsonObject>* PointObj = nullptr;
|
|
185
|
-
if ((*PointsArray)[i]->TryGetObject(PointObj))
|
|
186
|
-
{
|
|
187
|
-
FVector Point = FVector::ZeroVector;
|
|
188
|
-
(*PointObj)->TryGetNumberField(TEXT("x"), Point.X);
|
|
189
|
-
(*PointObj)->TryGetNumberField(TEXT("y"), Point.Y);
|
|
190
|
-
(*PointObj)->TryGetNumberField(TEXT("z"), Point.Z);
|
|
191
|
-
SplineComp->AddSplinePoint(Point, ESplineCoordinateSpace::World, false);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Optionally set closed loop
|
|
196
|
-
bool bClosedLoop = false;
|
|
197
|
-
if (Params->TryGetBoolField(TEXT("closedLoop"), bClosedLoop))
|
|
198
|
-
{
|
|
199
|
-
SplineComp->SetClosedLoop(bClosedLoop);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
SplineComp->UpdateSpline();
|
|
203
|
-
|
|
204
|
-
auto Result = MCPSuccess();
|
|
205
|
-
MCPSetUpdated(Result);
|
|
206
|
-
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
207
|
-
Result->SetNumberField(TEXT("splinePointCount"), SplineComp->GetNumberOfSplinePoints());
|
|
208
|
-
Result->SetBoolField(TEXT("closedLoop"), SplineComp->IsClosedLoop());
|
|
209
|
-
Result->SetNumberField(TEXT("splineLength"), SplineComp->GetSplineLength());
|
|
210
|
-
|
|
211
|
-
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
212
|
-
Payload->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
213
|
-
Payload->SetArrayField(TEXT("points"), PrevPoints);
|
|
214
|
-
Payload->SetBoolField(TEXT("closedLoop"), bPrevClosedLoop);
|
|
215
|
-
MCPSetRollback(Result, TEXT("set_spline_points"), Payload);
|
|
216
|
-
|
|
217
|
-
return MCPResult(Result);
|
|
218
|
-
}
|
|
1
|
+
#include "SplineHandlers.h"
|
|
2
|
+
#include "HandlerRegistry.h"
|
|
3
|
+
#include "HandlerUtils.h"
|
|
4
|
+
#include "Components/SplineComponent.h"
|
|
5
|
+
#include "Engine/World.h"
|
|
6
|
+
#include "Editor.h"
|
|
7
|
+
#include "Editor/EditorEngine.h"
|
|
8
|
+
#include "GameFramework/Actor.h"
|
|
9
|
+
#include "EngineUtils.h"
|
|
10
|
+
#include "Dom/JsonObject.h"
|
|
11
|
+
#include "Dom/JsonValue.h"
|
|
12
|
+
|
|
13
|
+
void FSplineHandlers::RegisterHandlers(FMCPHandlerRegistry& Registry)
|
|
14
|
+
{
|
|
15
|
+
Registry.RegisterHandler(TEXT("get_spline_info"), &ReadSpline);
|
|
16
|
+
Registry.RegisterHandler(TEXT("set_spline_points"), &SetSplinePoints);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
TSharedPtr<FJsonValue> FSplineHandlers::ReadSpline(const TSharedPtr<FJsonObject>& Params)
|
|
20
|
+
{
|
|
21
|
+
FString ActorLabel;
|
|
22
|
+
if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
|
|
23
|
+
|
|
24
|
+
// #553: support editor or PIE world so runtime spline state is readable.
|
|
25
|
+
const FString WorldScope = OptionalString(Params, TEXT("world"), TEXT("editor"));
|
|
26
|
+
UWorld* World = ResolveWorldFromParams(Params, *WorldScope);
|
|
27
|
+
if (!World) return MCPError(TEXT("World not available"));
|
|
28
|
+
|
|
29
|
+
AActor* Actor = FindActorByLabelOrName(World, ActorLabel);
|
|
30
|
+
if (!Actor)
|
|
31
|
+
{
|
|
32
|
+
return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// #553: optional componentName to target a specific (custom) spline component
|
|
36
|
+
// when an actor has more than one. Custom spline subclasses derive from
|
|
37
|
+
// USplineComponent, so FindComponentByClass still resolves them.
|
|
38
|
+
USplineComponent* SplineComp = nullptr;
|
|
39
|
+
const FString ComponentName = OptionalString(Params, TEXT("componentName"));
|
|
40
|
+
if (!ComponentName.IsEmpty())
|
|
41
|
+
{
|
|
42
|
+
TArray<USplineComponent*> Comps;
|
|
43
|
+
Actor->GetComponents<USplineComponent>(Comps);
|
|
44
|
+
for (USplineComponent* C : Comps)
|
|
45
|
+
{
|
|
46
|
+
if (C && C->GetName() == ComponentName) { SplineComp = C; break; }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
{
|
|
51
|
+
SplineComp = Actor->FindComponentByClass<USplineComponent>();
|
|
52
|
+
}
|
|
53
|
+
if (!SplineComp)
|
|
54
|
+
{
|
|
55
|
+
return MCPError(FString::Printf(TEXT("Actor '%s' has no matching SplineComponent"), *ActorLabel));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
auto Result = MCPSuccess();
|
|
59
|
+
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
60
|
+
Result->SetStringField(TEXT("componentName"), SplineComp->GetName());
|
|
61
|
+
Result->SetStringField(TEXT("componentClass"), SplineComp->GetClass()->GetName());
|
|
62
|
+
Result->SetNumberField(TEXT("splinePointCount"), SplineComp->GetNumberOfSplinePoints());
|
|
63
|
+
Result->SetBoolField(TEXT("closedLoop"), SplineComp->IsClosedLoop());
|
|
64
|
+
Result->SetNumberField(TEXT("splineLength"), SplineComp->GetSplineLength());
|
|
65
|
+
|
|
66
|
+
// #555: project a world point onto the spline. Returns the closest location,
|
|
67
|
+
// the input key, distance along the spline, and the perpendicular distance.
|
|
68
|
+
if (Params->HasField(TEXT("projectPoint")))
|
|
69
|
+
{
|
|
70
|
+
const FVector P = OptionalVec3(Params, TEXT("projectPoint"), FVector::ZeroVector);
|
|
71
|
+
const FVector Closest = SplineComp->FindLocationClosestToWorldLocation(P, ESplineCoordinateSpace::World);
|
|
72
|
+
const float InputKey = SplineComp->FindInputKeyClosestToWorldLocation(P);
|
|
73
|
+
const float DistAlong = SplineComp->GetDistanceAlongSplineAtSplineInputKey(InputKey);
|
|
74
|
+
TSharedPtr<FJsonObject> Proj = MakeShared<FJsonObject>();
|
|
75
|
+
Proj->SetObjectField(TEXT("closestLocation"), MCPVec3ToJsonObject(Closest));
|
|
76
|
+
Proj->SetNumberField(TEXT("inputKey"), InputKey);
|
|
77
|
+
Proj->SetNumberField(TEXT("distanceAlongSpline"), DistAlong);
|
|
78
|
+
Proj->SetNumberField(TEXT("distanceToSpline"), FVector::Dist(P, Closest));
|
|
79
|
+
Proj->SetObjectField(TEXT("tangent"), MCPVec3ToJsonObject(SplineComp->GetTangentAtDistanceAlongSpline(DistAlong, ESplineCoordinateSpace::World)));
|
|
80
|
+
Result->SetObjectField(TEXT("projection"), Proj);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Return all control points with world-space locations
|
|
84
|
+
TArray<TSharedPtr<FJsonValue>> PointsArray;
|
|
85
|
+
for (int32 i = 0; i < SplineComp->GetNumberOfSplinePoints(); ++i)
|
|
86
|
+
{
|
|
87
|
+
TSharedPtr<FJsonObject> PointObj = MakeShared<FJsonObject>();
|
|
88
|
+
PointObj->SetNumberField(TEXT("index"), i);
|
|
89
|
+
|
|
90
|
+
FVector WorldPos = SplineComp->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
91
|
+
TSharedPtr<FJsonObject> LocationObj = MakeShared<FJsonObject>();
|
|
92
|
+
LocationObj->SetNumberField(TEXT("x"), WorldPos.X);
|
|
93
|
+
LocationObj->SetNumberField(TEXT("y"), WorldPos.Y);
|
|
94
|
+
LocationObj->SetNumberField(TEXT("z"), WorldPos.Z);
|
|
95
|
+
PointObj->SetObjectField(TEXT("worldLocation"), LocationObj);
|
|
96
|
+
|
|
97
|
+
FVector LocalPos = SplineComp->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::Local);
|
|
98
|
+
TSharedPtr<FJsonObject> LocalObj = MakeShared<FJsonObject>();
|
|
99
|
+
LocalObj->SetNumberField(TEXT("x"), LocalPos.X);
|
|
100
|
+
LocalObj->SetNumberField(TEXT("y"), LocalPos.Y);
|
|
101
|
+
LocalObj->SetNumberField(TEXT("z"), LocalPos.Z);
|
|
102
|
+
PointObj->SetObjectField(TEXT("localLocation"), LocalObj);
|
|
103
|
+
|
|
104
|
+
FVector ArriveTangent = SplineComp->GetArriveTangentAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
105
|
+
TSharedPtr<FJsonObject> ArriveObj = MakeShared<FJsonObject>();
|
|
106
|
+
ArriveObj->SetNumberField(TEXT("x"), ArriveTangent.X);
|
|
107
|
+
ArriveObj->SetNumberField(TEXT("y"), ArriveTangent.Y);
|
|
108
|
+
ArriveObj->SetNumberField(TEXT("z"), ArriveTangent.Z);
|
|
109
|
+
PointObj->SetObjectField(TEXT("arriveTangent"), ArriveObj);
|
|
110
|
+
|
|
111
|
+
FVector LeaveTangent = SplineComp->GetLeaveTangentAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
112
|
+
TSharedPtr<FJsonObject> LeaveObj = MakeShared<FJsonObject>();
|
|
113
|
+
LeaveObj->SetNumberField(TEXT("x"), LeaveTangent.X);
|
|
114
|
+
LeaveObj->SetNumberField(TEXT("y"), LeaveTangent.Y);
|
|
115
|
+
LeaveObj->SetNumberField(TEXT("z"), LeaveTangent.Z);
|
|
116
|
+
PointObj->SetObjectField(TEXT("leaveTangent"), LeaveObj);
|
|
117
|
+
|
|
118
|
+
// Point type
|
|
119
|
+
ESplinePointType::Type PointType = SplineComp->GetSplinePointType(i);
|
|
120
|
+
FString PointTypeStr;
|
|
121
|
+
switch (PointType)
|
|
122
|
+
{
|
|
123
|
+
case ESplinePointType::Linear: PointTypeStr = TEXT("Linear"); break;
|
|
124
|
+
case ESplinePointType::Curve: PointTypeStr = TEXT("Curve"); break;
|
|
125
|
+
case ESplinePointType::Constant: PointTypeStr = TEXT("Constant"); break;
|
|
126
|
+
case ESplinePointType::CurveClamped: PointTypeStr = TEXT("CurveClamped"); break;
|
|
127
|
+
case ESplinePointType::CurveCustomTangent: PointTypeStr = TEXT("CurveCustomTangent"); break;
|
|
128
|
+
default: PointTypeStr = TEXT("Unknown"); break;
|
|
129
|
+
}
|
|
130
|
+
PointObj->SetStringField(TEXT("pointType"), PointTypeStr);
|
|
131
|
+
|
|
132
|
+
PointsArray.Add(MakeShared<FJsonValueObject>(PointObj));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
Result->SetArrayField(TEXT("points"), PointsArray);
|
|
136
|
+
|
|
137
|
+
return MCPResult(Result);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
TSharedPtr<FJsonValue> FSplineHandlers::SetSplinePoints(const TSharedPtr<FJsonObject>& Params)
|
|
141
|
+
{
|
|
142
|
+
FString ActorLabel;
|
|
143
|
+
if (auto Err = RequireString(Params, TEXT("actorLabel"), ActorLabel)) return Err;
|
|
144
|
+
|
|
145
|
+
const TArray<TSharedPtr<FJsonValue>>* PointsArray = nullptr;
|
|
146
|
+
if (!Params->TryGetArrayField(TEXT("points"), PointsArray))
|
|
147
|
+
{
|
|
148
|
+
return MCPError(TEXT("Missing 'points' parameter (array of {x, y, z} objects)"));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
REQUIRE_EDITOR_WORLD(World);
|
|
152
|
+
|
|
153
|
+
AActor* Actor = FindActorByLabel(World, ActorLabel);
|
|
154
|
+
if (!Actor)
|
|
155
|
+
{
|
|
156
|
+
return MCPError(FString::Printf(TEXT("Actor not found: %s"), *ActorLabel));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Find spline component
|
|
160
|
+
USplineComponent* SplineComp = Actor->FindComponentByClass<USplineComponent>();
|
|
161
|
+
if (!SplineComp)
|
|
162
|
+
{
|
|
163
|
+
return MCPError(FString::Printf(TEXT("Actor '%s' does not have a SplineComponent"), *ActorLabel));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Capture previous spline points for rollback
|
|
167
|
+
TArray<TSharedPtr<FJsonValue>> PrevPoints;
|
|
168
|
+
for (int32 i = 0; i < SplineComp->GetNumberOfSplinePoints(); ++i)
|
|
169
|
+
{
|
|
170
|
+
FVector P = SplineComp->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
|
|
171
|
+
TSharedPtr<FJsonObject> PObj = MakeShared<FJsonObject>();
|
|
172
|
+
PObj->SetNumberField(TEXT("x"), P.X);
|
|
173
|
+
PObj->SetNumberField(TEXT("y"), P.Y);
|
|
174
|
+
PObj->SetNumberField(TEXT("z"), P.Z);
|
|
175
|
+
PrevPoints.Add(MakeShared<FJsonValueObject>(PObj));
|
|
176
|
+
}
|
|
177
|
+
const bool bPrevClosedLoop = SplineComp->IsClosedLoop();
|
|
178
|
+
|
|
179
|
+
// Clear existing points and add new ones
|
|
180
|
+
SplineComp->ClearSplinePoints(false);
|
|
181
|
+
|
|
182
|
+
for (int32 i = 0; i < PointsArray->Num(); ++i)
|
|
183
|
+
{
|
|
184
|
+
const TSharedPtr<FJsonObject>* PointObj = nullptr;
|
|
185
|
+
if ((*PointsArray)[i]->TryGetObject(PointObj))
|
|
186
|
+
{
|
|
187
|
+
FVector Point = FVector::ZeroVector;
|
|
188
|
+
(*PointObj)->TryGetNumberField(TEXT("x"), Point.X);
|
|
189
|
+
(*PointObj)->TryGetNumberField(TEXT("y"), Point.Y);
|
|
190
|
+
(*PointObj)->TryGetNumberField(TEXT("z"), Point.Z);
|
|
191
|
+
SplineComp->AddSplinePoint(Point, ESplineCoordinateSpace::World, false);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Optionally set closed loop
|
|
196
|
+
bool bClosedLoop = false;
|
|
197
|
+
if (Params->TryGetBoolField(TEXT("closedLoop"), bClosedLoop))
|
|
198
|
+
{
|
|
199
|
+
SplineComp->SetClosedLoop(bClosedLoop);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
SplineComp->UpdateSpline();
|
|
203
|
+
|
|
204
|
+
auto Result = MCPSuccess();
|
|
205
|
+
MCPSetUpdated(Result);
|
|
206
|
+
Result->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
207
|
+
Result->SetNumberField(TEXT("splinePointCount"), SplineComp->GetNumberOfSplinePoints());
|
|
208
|
+
Result->SetBoolField(TEXT("closedLoop"), SplineComp->IsClosedLoop());
|
|
209
|
+
Result->SetNumberField(TEXT("splineLength"), SplineComp->GetSplineLength());
|
|
210
|
+
|
|
211
|
+
TSharedPtr<FJsonObject> Payload = MakeShared<FJsonObject>();
|
|
212
|
+
Payload->SetStringField(TEXT("actorLabel"), ActorLabel);
|
|
213
|
+
Payload->SetArrayField(TEXT("points"), PrevPoints);
|
|
214
|
+
Payload->SetBoolField(TEXT("closedLoop"), bPrevClosedLoop);
|
|
215
|
+
MCPSetRollback(Result, TEXT("set_spline_points"), Payload);
|
|
216
|
+
|
|
217
|
+
return MCPResult(Result);
|
|
218
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "CoreMinimal.h"
|
|
4
|
-
#include "Dom/JsonValue.h"
|
|
5
|
-
#include "Dom/JsonObject.h"
|
|
6
|
-
|
|
7
|
-
class FSplineHandlers
|
|
8
|
-
{
|
|
9
|
-
public:
|
|
10
|
-
// Register all spline handlers
|
|
11
|
-
static void RegisterHandlers(class FMCPHandlerRegistry& Registry);
|
|
12
|
-
|
|
13
|
-
private:
|
|
14
|
-
// Handler implementations
|
|
15
|
-
static TSharedPtr<FJsonValue> ReadSpline(const TSharedPtr<FJsonObject>& Params);
|
|
16
|
-
static TSharedPtr<FJsonValue> SetSplinePoints(const TSharedPtr<FJsonObject>& Params);
|
|
17
|
-
};
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "CoreMinimal.h"
|
|
4
|
+
#include "Dom/JsonValue.h"
|
|
5
|
+
#include "Dom/JsonObject.h"
|
|
6
|
+
|
|
7
|
+
class FSplineHandlers
|
|
8
|
+
{
|
|
9
|
+
public:
|
|
10
|
+
// Register all spline handlers
|
|
11
|
+
static void RegisterHandlers(class FMCPHandlerRegistry& Registry);
|
|
12
|
+
|
|
13
|
+
private:
|
|
14
|
+
// Handler implementations
|
|
15
|
+
static TSharedPtr<FJsonValue> ReadSpline(const TSharedPtr<FJsonObject>& Params);
|
|
16
|
+
static TSharedPtr<FJsonValue> SetSplinePoints(const TSharedPtr<FJsonObject>& Params);
|
|
17
|
+
};
|
package/plugin/ue_mcp_bridge/Source/UE_MCP_Bridge/Private/Handlers/VolumeHelpers_Internal.cpp
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
#include "VolumeHelpers_Internal.h"
|
|
2
|
-
|
|
3
|
-
#include "Engine/World.h"
|
|
4
|
-
#include "Engine/Brush.h"
|
|
5
|
-
#include "Engine/Polys.h"
|
|
6
|
-
#include "Components/BrushComponent.h"
|
|
7
|
-
#include "Builders/CubeBuilder.h"
|
|
8
|
-
#include "BSPOps.h"
|
|
9
|
-
#include "Model.h"
|
|
10
|
-
#include "GameFramework/Volume.h"
|
|
11
|
-
#include "UObject/UObjectGlobals.h"
|
|
12
|
-
#include "UObject/Package.h"
|
|
13
|
-
|
|
14
|
-
namespace UEMCP
|
|
15
|
-
{
|
|
16
|
-
void BuildVolumeAsCube(UWorld* World, AVolume* Volume, const FVector& HalfExtent)
|
|
17
|
-
{
|
|
18
|
-
if (!World || !Volume) return;
|
|
19
|
-
|
|
20
|
-
Volume->PreEditChange(nullptr);
|
|
21
|
-
|
|
22
|
-
if (!Volume->Brush)
|
|
23
|
-
{
|
|
24
|
-
const EObjectFlags ObjectFlags = Volume->GetFlags() & (RF_Transient | RF_Transactional);
|
|
25
|
-
Volume->PolyFlags = 0;
|
|
26
|
-
Volume->Brush = NewObject<UModel>(Volume, NAME_None, ObjectFlags);
|
|
27
|
-
Volume->Brush->Initialize(nullptr, true);
|
|
28
|
-
Volume->Brush->Polys = NewObject<UPolys>(Volume->Brush, NAME_None, ObjectFlags);
|
|
29
|
-
if (UBrushComponent* BC = Volume->GetBrushComponent())
|
|
30
|
-
{
|
|
31
|
-
BC->Brush = Volume->Brush;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
UCubeBuilder* CubeBuilder = NewObject<UCubeBuilder>(GetTransientPackage(), UCubeBuilder::StaticClass());
|
|
36
|
-
CubeBuilder->X = HalfExtent.X * 2.0;
|
|
37
|
-
CubeBuilder->Y = HalfExtent.Y * 2.0;
|
|
38
|
-
CubeBuilder->Z = HalfExtent.Z * 2.0;
|
|
39
|
-
CubeBuilder->Build(World, Volume);
|
|
40
|
-
|
|
41
|
-
Volume->BrushBuilder = CubeBuilder;
|
|
42
|
-
Volume->SetActorScale3D(FVector::OneVector);
|
|
43
|
-
|
|
44
|
-
FBSPOps::csgPrepMovingBrush(Volume);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
#include "VolumeHelpers_Internal.h"
|
|
2
|
+
|
|
3
|
+
#include "Engine/World.h"
|
|
4
|
+
#include "Engine/Brush.h"
|
|
5
|
+
#include "Engine/Polys.h"
|
|
6
|
+
#include "Components/BrushComponent.h"
|
|
7
|
+
#include "Builders/CubeBuilder.h"
|
|
8
|
+
#include "BSPOps.h"
|
|
9
|
+
#include "Model.h"
|
|
10
|
+
#include "GameFramework/Volume.h"
|
|
11
|
+
#include "UObject/UObjectGlobals.h"
|
|
12
|
+
#include "UObject/Package.h"
|
|
13
|
+
|
|
14
|
+
namespace UEMCP
|
|
15
|
+
{
|
|
16
|
+
void BuildVolumeAsCube(UWorld* World, AVolume* Volume, const FVector& HalfExtent)
|
|
17
|
+
{
|
|
18
|
+
if (!World || !Volume) return;
|
|
19
|
+
|
|
20
|
+
Volume->PreEditChange(nullptr);
|
|
21
|
+
|
|
22
|
+
if (!Volume->Brush)
|
|
23
|
+
{
|
|
24
|
+
const EObjectFlags ObjectFlags = Volume->GetFlags() & (RF_Transient | RF_Transactional);
|
|
25
|
+
Volume->PolyFlags = 0;
|
|
26
|
+
Volume->Brush = NewObject<UModel>(Volume, NAME_None, ObjectFlags);
|
|
27
|
+
Volume->Brush->Initialize(nullptr, true);
|
|
28
|
+
Volume->Brush->Polys = NewObject<UPolys>(Volume->Brush, NAME_None, ObjectFlags);
|
|
29
|
+
if (UBrushComponent* BC = Volume->GetBrushComponent())
|
|
30
|
+
{
|
|
31
|
+
BC->Brush = Volume->Brush;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
UCubeBuilder* CubeBuilder = NewObject<UCubeBuilder>(GetTransientPackage(), UCubeBuilder::StaticClass());
|
|
36
|
+
CubeBuilder->X = HalfExtent.X * 2.0;
|
|
37
|
+
CubeBuilder->Y = HalfExtent.Y * 2.0;
|
|
38
|
+
CubeBuilder->Z = HalfExtent.Z * 2.0;
|
|
39
|
+
CubeBuilder->Build(World, Volume);
|
|
40
|
+
|
|
41
|
+
Volume->BrushBuilder = CubeBuilder;
|
|
42
|
+
Volume->SetActorScale3D(FVector::OneVector);
|
|
43
|
+
|
|
44
|
+
FBSPOps::csgPrepMovingBrush(Volume);
|
|
45
|
+
}
|
|
46
|
+
}
|