flockbay 0.10.15
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 +56 -0
- package/bin/flockbay-mcp.mjs +56 -0
- package/bin/flockbay.mjs +78 -0
- package/dist/codex/flockbayMcpStdioBridge.cjs +383 -0
- package/dist/codex/flockbayMcpStdioBridge.d.cts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.d.mts +2 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +381 -0
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +136 -0
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +138 -0
- package/dist/index--o4BPz5o.cjs +10311 -0
- package/dist/index-CUp3juDS.mjs +10268 -0
- package/dist/index.cjs +43 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +40 -0
- package/dist/lib.cjs +33 -0
- package/dist/lib.d.cts +957 -0
- package/dist/lib.d.mts +957 -0
- package/dist/lib.mjs +23 -0
- package/dist/runCodex-D3eT-TvB.cjs +3449 -0
- package/dist/runCodex-o6PCbHQ7.mjs +3446 -0
- package/dist/runGemini-Bt0oEj_g.mjs +3183 -0
- package/dist/runGemini-CBxZp6I7.cjs +3185 -0
- package/dist/types-C-jnUdn_.cjs +4498 -0
- package/dist/types-DGd6ea2Z.mjs +4450 -0
- package/kits/kit.open_world/kit.json +59 -0
- package/package.json +130 -0
- package/scripts/claude_local_launcher.cjs +73 -0
- package/scripts/claude_remote_launcher.cjs +16 -0
- package/scripts/claude_version_utils.cjs +391 -0
- package/scripts/ripgrep_launcher.cjs +33 -0
- package/scripts/session_hook_forwarder.cjs +49 -0
- package/scripts/test-codex-abort-history.mjs +77 -0
- package/scripts/unpack-tools.cjs +222 -0
- package/tools/licenses/difftastic-LICENSE +21 -0
- package/tools/licenses/ripgrep-LICENSE +3 -0
- package/tools/unreal-mcp/UPSTREAM_VERSION.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/README.md +8 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/README.md +7 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/actor_tools.md +184 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/blueprint_tools.md +268 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/editor_tools.md +104 -0
- package/tools/unreal-mcp/upstream/Docs/Tools/node_tools.md +274 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Config/FilterPlugin.ini +8 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +1160 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +924 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +709 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +896 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPProjectCommands.cpp +72 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPUMGCommands.cpp +544 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +321 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +419 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPModule.cpp +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +27 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommonUtils.h +59 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +40 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPProjectCommands.h +20 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPUMGCommands.h +82 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/MCPServerRunnable.h +34 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPBridge.h +64 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/UnrealMCPModule.h +22 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +78 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/UnrealMCP.uplugin +36 -0
- package/tools/unreal-mcp/upstream/Python/README.md +40 -0
- package/tools/unreal-mcp/upstream/Python/pyproject.toml +22 -0
- package/tools/unreal-mcp/upstream/Python/scripts/actors/test_cube.py +203 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_blueprints_with_different_components.py +497 -0
- package/tools/unreal-mcp/upstream/Python/scripts/blueprints/test_create_and_spawn_cube_blueprint.py +194 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_component_reference.py +267 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_create_bird_blueprint_with_input_and_camera.py +618 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_input_mapping.py +366 -0
- package/tools/unreal-mcp/upstream/Python/scripts/node/test_physics_variables.py +390 -0
- package/tools/unreal-mcp/upstream/Python/tools/blueprint_tools.py +420 -0
- package/tools/unreal-mcp/upstream/Python/tools/editor_tools.py +369 -0
- package/tools/unreal-mcp/upstream/Python/tools/node_tools.py +430 -0
- package/tools/unreal-mcp/upstream/Python/tools/project_tools.py +64 -0
- package/tools/unreal-mcp/upstream/Python/tools/umg_tools.py +333 -0
- package/tools/unreal-mcp/upstream/Python/unreal_mcp_server.py +398 -0
- package/tools/unreal-mcp/upstream/Python/uv.lock +521 -0
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
#include "Commands/UnrealMCPCommonUtils.h"
|
|
2
|
+
#include "GameFramework/Actor.h"
|
|
3
|
+
#include "Engine/Blueprint.h"
|
|
4
|
+
#include "EdGraph/EdGraph.h"
|
|
5
|
+
#include "EdGraph/EdGraphNode.h"
|
|
6
|
+
#include "EdGraph/EdGraphPin.h"
|
|
7
|
+
#include "K2Node_Event.h"
|
|
8
|
+
#include "K2Node_CallFunction.h"
|
|
9
|
+
#include "K2Node_VariableGet.h"
|
|
10
|
+
#include "K2Node_VariableSet.h"
|
|
11
|
+
#include "K2Node_InputAction.h"
|
|
12
|
+
#include "K2Node_Self.h"
|
|
13
|
+
#include "EdGraphSchema_K2.h"
|
|
14
|
+
#include "Kismet2/BlueprintEditorUtils.h"
|
|
15
|
+
#include "Components/StaticMeshComponent.h"
|
|
16
|
+
#include "Components/LightComponent.h"
|
|
17
|
+
#include "Components/PrimitiveComponent.h"
|
|
18
|
+
#include "Components/SceneComponent.h"
|
|
19
|
+
#include "UObject/UObjectIterator.h"
|
|
20
|
+
#include "Engine/Selection.h"
|
|
21
|
+
#include "EditorAssetLibrary.h"
|
|
22
|
+
#include "AssetRegistry/AssetRegistryModule.h"
|
|
23
|
+
#include "Engine/BlueprintGeneratedClass.h"
|
|
24
|
+
#include "BlueprintNodeSpawner.h"
|
|
25
|
+
#include "BlueprintActionDatabase.h"
|
|
26
|
+
#include "Dom/JsonObject.h"
|
|
27
|
+
#include "Dom/JsonValue.h"
|
|
28
|
+
|
|
29
|
+
// JSON Utilities
|
|
30
|
+
TSharedPtr<FJsonObject> FUnrealMCPCommonUtils::CreateErrorResponse(const FString& Message)
|
|
31
|
+
{
|
|
32
|
+
TSharedPtr<FJsonObject> ResponseObject = MakeShared<FJsonObject>();
|
|
33
|
+
ResponseObject->SetBoolField(TEXT("success"), false);
|
|
34
|
+
ResponseObject->SetStringField(TEXT("error"), Message);
|
|
35
|
+
return ResponseObject;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
TSharedPtr<FJsonObject> FUnrealMCPCommonUtils::CreateSuccessResponse(const TSharedPtr<FJsonObject>& Data)
|
|
39
|
+
{
|
|
40
|
+
TSharedPtr<FJsonObject> ResponseObject = MakeShared<FJsonObject>();
|
|
41
|
+
ResponseObject->SetBoolField(TEXT("success"), true);
|
|
42
|
+
|
|
43
|
+
if (Data.IsValid())
|
|
44
|
+
{
|
|
45
|
+
ResponseObject->SetObjectField(TEXT("data"), Data);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return ResponseObject;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void FUnrealMCPCommonUtils::GetIntArrayFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName, TArray<int32>& OutArray)
|
|
52
|
+
{
|
|
53
|
+
OutArray.Reset();
|
|
54
|
+
|
|
55
|
+
if (!JsonObject->HasField(FieldName))
|
|
56
|
+
{
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const TArray<TSharedPtr<FJsonValue>>* JsonArray;
|
|
61
|
+
if (JsonObject->TryGetArrayField(FieldName, JsonArray))
|
|
62
|
+
{
|
|
63
|
+
for (const TSharedPtr<FJsonValue>& Value : *JsonArray)
|
|
64
|
+
{
|
|
65
|
+
OutArray.Add((int32)Value->AsNumber());
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
void FUnrealMCPCommonUtils::GetFloatArrayFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName, TArray<float>& OutArray)
|
|
71
|
+
{
|
|
72
|
+
OutArray.Reset();
|
|
73
|
+
|
|
74
|
+
if (!JsonObject->HasField(FieldName))
|
|
75
|
+
{
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const TArray<TSharedPtr<FJsonValue>>* JsonArray;
|
|
80
|
+
if (JsonObject->TryGetArrayField(FieldName, JsonArray))
|
|
81
|
+
{
|
|
82
|
+
for (const TSharedPtr<FJsonValue>& Value : *JsonArray)
|
|
83
|
+
{
|
|
84
|
+
OutArray.Add((float)Value->AsNumber());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
FVector2D FUnrealMCPCommonUtils::GetVector2DFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName)
|
|
90
|
+
{
|
|
91
|
+
FVector2D Result(0.0f, 0.0f);
|
|
92
|
+
|
|
93
|
+
if (!JsonObject->HasField(FieldName))
|
|
94
|
+
{
|
|
95
|
+
return Result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const TArray<TSharedPtr<FJsonValue>>* JsonArray;
|
|
99
|
+
if (JsonObject->TryGetArrayField(FieldName, JsonArray) && JsonArray->Num() >= 2)
|
|
100
|
+
{
|
|
101
|
+
Result.X = (float)(*JsonArray)[0]->AsNumber();
|
|
102
|
+
Result.Y = (float)(*JsonArray)[1]->AsNumber();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return Result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
FVector FUnrealMCPCommonUtils::GetVectorFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName)
|
|
109
|
+
{
|
|
110
|
+
FVector Result(0.0f, 0.0f, 0.0f);
|
|
111
|
+
|
|
112
|
+
if (!JsonObject->HasField(FieldName))
|
|
113
|
+
{
|
|
114
|
+
return Result;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const TArray<TSharedPtr<FJsonValue>>* JsonArray;
|
|
118
|
+
if (JsonObject->TryGetArrayField(FieldName, JsonArray) && JsonArray->Num() >= 3)
|
|
119
|
+
{
|
|
120
|
+
Result.X = (float)(*JsonArray)[0]->AsNumber();
|
|
121
|
+
Result.Y = (float)(*JsonArray)[1]->AsNumber();
|
|
122
|
+
Result.Z = (float)(*JsonArray)[2]->AsNumber();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return Result;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
FRotator FUnrealMCPCommonUtils::GetRotatorFromJson(const TSharedPtr<FJsonObject>& JsonObject, const FString& FieldName)
|
|
129
|
+
{
|
|
130
|
+
FRotator Result(0.0f, 0.0f, 0.0f);
|
|
131
|
+
|
|
132
|
+
if (!JsonObject->HasField(FieldName))
|
|
133
|
+
{
|
|
134
|
+
return Result;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const TArray<TSharedPtr<FJsonValue>>* JsonArray;
|
|
138
|
+
if (JsonObject->TryGetArrayField(FieldName, JsonArray) && JsonArray->Num() >= 3)
|
|
139
|
+
{
|
|
140
|
+
Result.Pitch = (float)(*JsonArray)[0]->AsNumber();
|
|
141
|
+
Result.Yaw = (float)(*JsonArray)[1]->AsNumber();
|
|
142
|
+
Result.Roll = (float)(*JsonArray)[2]->AsNumber();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return Result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Blueprint Utilities
|
|
149
|
+
UBlueprint* FUnrealMCPCommonUtils::FindBlueprint(const FString& BlueprintName)
|
|
150
|
+
{
|
|
151
|
+
return FindBlueprintByName(BlueprintName);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
UBlueprint* FUnrealMCPCommonUtils::FindBlueprintByName(const FString& BlueprintName)
|
|
155
|
+
{
|
|
156
|
+
FString AssetPath = TEXT("/Game/Blueprints/") + BlueprintName;
|
|
157
|
+
return LoadObject<UBlueprint>(nullptr, *AssetPath);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
UEdGraph* FUnrealMCPCommonUtils::FindOrCreateEventGraph(UBlueprint* Blueprint)
|
|
161
|
+
{
|
|
162
|
+
if (!Blueprint)
|
|
163
|
+
{
|
|
164
|
+
return nullptr;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Try to find the event graph
|
|
168
|
+
for (UEdGraph* Graph : Blueprint->UbergraphPages)
|
|
169
|
+
{
|
|
170
|
+
if (Graph->GetName().Contains(TEXT("EventGraph")))
|
|
171
|
+
{
|
|
172
|
+
return Graph;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Create a new event graph if none exists
|
|
177
|
+
UEdGraph* NewGraph = FBlueprintEditorUtils::CreateNewGraph(Blueprint, FName(TEXT("EventGraph")), UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
|
|
178
|
+
FBlueprintEditorUtils::AddUbergraphPage(Blueprint, NewGraph);
|
|
179
|
+
return NewGraph;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Blueprint node utilities
|
|
183
|
+
UK2Node_Event* FUnrealMCPCommonUtils::CreateEventNode(UEdGraph* Graph, const FString& EventName, const FVector2D& Position)
|
|
184
|
+
{
|
|
185
|
+
if (!Graph)
|
|
186
|
+
{
|
|
187
|
+
return nullptr;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForGraph(Graph);
|
|
191
|
+
if (!Blueprint)
|
|
192
|
+
{
|
|
193
|
+
return nullptr;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Check for existing event node with this exact name
|
|
197
|
+
for (UEdGraphNode* Node : Graph->Nodes)
|
|
198
|
+
{
|
|
199
|
+
UK2Node_Event* EventNode = Cast<UK2Node_Event>(Node);
|
|
200
|
+
if (EventNode && EventNode->EventReference.GetMemberName() == FName(*EventName))
|
|
201
|
+
{
|
|
202
|
+
UE_LOG(LogTemp, Display, TEXT("Using existing event node with name %s (ID: %s)"),
|
|
203
|
+
*EventName, *EventNode->NodeGuid.ToString());
|
|
204
|
+
return EventNode;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// No existing node found, create a new one
|
|
209
|
+
UK2Node_Event* EventNode = nullptr;
|
|
210
|
+
|
|
211
|
+
// Find the function to create the event
|
|
212
|
+
UClass* BlueprintClass = Blueprint->GeneratedClass;
|
|
213
|
+
UFunction* EventFunction = BlueprintClass->FindFunctionByName(FName(*EventName));
|
|
214
|
+
|
|
215
|
+
if (EventFunction)
|
|
216
|
+
{
|
|
217
|
+
EventNode = NewObject<UK2Node_Event>(Graph);
|
|
218
|
+
EventNode->EventReference.SetExternalMember(FName(*EventName), BlueprintClass);
|
|
219
|
+
EventNode->NodePosX = Position.X;
|
|
220
|
+
EventNode->NodePosY = Position.Y;
|
|
221
|
+
Graph->AddNode(EventNode, true);
|
|
222
|
+
EventNode->PostPlacedNewNode();
|
|
223
|
+
EventNode->AllocateDefaultPins();
|
|
224
|
+
UE_LOG(LogTemp, Display, TEXT("Created new event node with name %s (ID: %s)"),
|
|
225
|
+
*EventName, *EventNode->NodeGuid.ToString());
|
|
226
|
+
}
|
|
227
|
+
else
|
|
228
|
+
{
|
|
229
|
+
UE_LOG(LogTemp, Error, TEXT("Failed to find function for event name: %s"), *EventName);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return EventNode;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
UK2Node_CallFunction* FUnrealMCPCommonUtils::CreateFunctionCallNode(UEdGraph* Graph, UFunction* Function, const FVector2D& Position)
|
|
236
|
+
{
|
|
237
|
+
if (!Graph || !Function)
|
|
238
|
+
{
|
|
239
|
+
return nullptr;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
UK2Node_CallFunction* FunctionNode = NewObject<UK2Node_CallFunction>(Graph);
|
|
243
|
+
FunctionNode->SetFromFunction(Function);
|
|
244
|
+
FunctionNode->NodePosX = Position.X;
|
|
245
|
+
FunctionNode->NodePosY = Position.Y;
|
|
246
|
+
Graph->AddNode(FunctionNode, true);
|
|
247
|
+
FunctionNode->CreateNewGuid();
|
|
248
|
+
FunctionNode->PostPlacedNewNode();
|
|
249
|
+
FunctionNode->AllocateDefaultPins();
|
|
250
|
+
|
|
251
|
+
return FunctionNode;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
UK2Node_VariableGet* FUnrealMCPCommonUtils::CreateVariableGetNode(UEdGraph* Graph, UBlueprint* Blueprint, const FString& VariableName, const FVector2D& Position)
|
|
255
|
+
{
|
|
256
|
+
if (!Graph || !Blueprint)
|
|
257
|
+
{
|
|
258
|
+
return nullptr;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
UK2Node_VariableGet* VariableGetNode = NewObject<UK2Node_VariableGet>(Graph);
|
|
262
|
+
|
|
263
|
+
FName VarName(*VariableName);
|
|
264
|
+
FProperty* Property = FindFProperty<FProperty>(Blueprint->GeneratedClass, VarName);
|
|
265
|
+
|
|
266
|
+
if (Property)
|
|
267
|
+
{
|
|
268
|
+
VariableGetNode->VariableReference.SetFromField<FProperty>(Property, false);
|
|
269
|
+
VariableGetNode->NodePosX = Position.X;
|
|
270
|
+
VariableGetNode->NodePosY = Position.Y;
|
|
271
|
+
Graph->AddNode(VariableGetNode, true);
|
|
272
|
+
VariableGetNode->PostPlacedNewNode();
|
|
273
|
+
VariableGetNode->AllocateDefaultPins();
|
|
274
|
+
|
|
275
|
+
return VariableGetNode;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return nullptr;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
UK2Node_VariableSet* FUnrealMCPCommonUtils::CreateVariableSetNode(UEdGraph* Graph, UBlueprint* Blueprint, const FString& VariableName, const FVector2D& Position)
|
|
282
|
+
{
|
|
283
|
+
if (!Graph || !Blueprint)
|
|
284
|
+
{
|
|
285
|
+
return nullptr;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
UK2Node_VariableSet* VariableSetNode = NewObject<UK2Node_VariableSet>(Graph);
|
|
289
|
+
|
|
290
|
+
FName VarName(*VariableName);
|
|
291
|
+
FProperty* Property = FindFProperty<FProperty>(Blueprint->GeneratedClass, VarName);
|
|
292
|
+
|
|
293
|
+
if (Property)
|
|
294
|
+
{
|
|
295
|
+
VariableSetNode->VariableReference.SetFromField<FProperty>(Property, false);
|
|
296
|
+
VariableSetNode->NodePosX = Position.X;
|
|
297
|
+
VariableSetNode->NodePosY = Position.Y;
|
|
298
|
+
Graph->AddNode(VariableSetNode, true);
|
|
299
|
+
VariableSetNode->PostPlacedNewNode();
|
|
300
|
+
VariableSetNode->AllocateDefaultPins();
|
|
301
|
+
|
|
302
|
+
return VariableSetNode;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return nullptr;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
UK2Node_InputAction* FUnrealMCPCommonUtils::CreateInputActionNode(UEdGraph* Graph, const FString& ActionName, const FVector2D& Position)
|
|
309
|
+
{
|
|
310
|
+
if (!Graph)
|
|
311
|
+
{
|
|
312
|
+
return nullptr;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
UK2Node_InputAction* InputActionNode = NewObject<UK2Node_InputAction>(Graph);
|
|
316
|
+
InputActionNode->InputActionName = FName(*ActionName);
|
|
317
|
+
InputActionNode->NodePosX = Position.X;
|
|
318
|
+
InputActionNode->NodePosY = Position.Y;
|
|
319
|
+
Graph->AddNode(InputActionNode, true);
|
|
320
|
+
InputActionNode->CreateNewGuid();
|
|
321
|
+
InputActionNode->PostPlacedNewNode();
|
|
322
|
+
InputActionNode->AllocateDefaultPins();
|
|
323
|
+
|
|
324
|
+
return InputActionNode;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
UK2Node_Self* FUnrealMCPCommonUtils::CreateSelfReferenceNode(UEdGraph* Graph, const FVector2D& Position)
|
|
328
|
+
{
|
|
329
|
+
if (!Graph)
|
|
330
|
+
{
|
|
331
|
+
return nullptr;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
UK2Node_Self* SelfNode = NewObject<UK2Node_Self>(Graph);
|
|
335
|
+
SelfNode->NodePosX = Position.X;
|
|
336
|
+
SelfNode->NodePosY = Position.Y;
|
|
337
|
+
Graph->AddNode(SelfNode, true);
|
|
338
|
+
SelfNode->CreateNewGuid();
|
|
339
|
+
SelfNode->PostPlacedNewNode();
|
|
340
|
+
SelfNode->AllocateDefaultPins();
|
|
341
|
+
|
|
342
|
+
return SelfNode;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
bool FUnrealMCPCommonUtils::ConnectGraphNodes(UEdGraph* Graph, UEdGraphNode* SourceNode, const FString& SourcePinName,
|
|
346
|
+
UEdGraphNode* TargetNode, const FString& TargetPinName)
|
|
347
|
+
{
|
|
348
|
+
if (!Graph || !SourceNode || !TargetNode)
|
|
349
|
+
{
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
UEdGraphPin* SourcePin = FindPin(SourceNode, SourcePinName, EGPD_Output);
|
|
354
|
+
UEdGraphPin* TargetPin = FindPin(TargetNode, TargetPinName, EGPD_Input);
|
|
355
|
+
|
|
356
|
+
if (SourcePin && TargetPin)
|
|
357
|
+
{
|
|
358
|
+
SourcePin->MakeLinkTo(TargetPin);
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
UEdGraphPin* FUnrealMCPCommonUtils::FindPin(UEdGraphNode* Node, const FString& PinName, EEdGraphPinDirection Direction)
|
|
366
|
+
{
|
|
367
|
+
if (!Node)
|
|
368
|
+
{
|
|
369
|
+
return nullptr;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Log all pins for debugging
|
|
373
|
+
UE_LOG(LogTemp, Display, TEXT("FindPin: Looking for pin '%s' (Direction: %d) in node '%s'"),
|
|
374
|
+
*PinName, (int32)Direction, *Node->GetName());
|
|
375
|
+
|
|
376
|
+
for (UEdGraphPin* Pin : Node->Pins)
|
|
377
|
+
{
|
|
378
|
+
UE_LOG(LogTemp, Display, TEXT(" - Available pin: '%s', Direction: %d, Category: %s"),
|
|
379
|
+
*Pin->PinName.ToString(), (int32)Pin->Direction, *Pin->PinType.PinCategory.ToString());
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// First try exact match
|
|
383
|
+
for (UEdGraphPin* Pin : Node->Pins)
|
|
384
|
+
{
|
|
385
|
+
if (Pin->PinName.ToString() == PinName && (Direction == EGPD_MAX || Pin->Direction == Direction))
|
|
386
|
+
{
|
|
387
|
+
UE_LOG(LogTemp, Display, TEXT(" - Found exact matching pin: '%s'"), *Pin->PinName.ToString());
|
|
388
|
+
return Pin;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// If no exact match and we're looking for a component reference, try case-insensitive match
|
|
393
|
+
for (UEdGraphPin* Pin : Node->Pins)
|
|
394
|
+
{
|
|
395
|
+
if (Pin->PinName.ToString().Equals(PinName, ESearchCase::IgnoreCase) &&
|
|
396
|
+
(Direction == EGPD_MAX || Pin->Direction == Direction))
|
|
397
|
+
{
|
|
398
|
+
UE_LOG(LogTemp, Display, TEXT(" - Found case-insensitive matching pin: '%s'"), *Pin->PinName.ToString());
|
|
399
|
+
return Pin;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// If we're looking for a component output and didn't find it by name, try to find the first data output pin
|
|
404
|
+
if (Direction == EGPD_Output && Cast<UK2Node_VariableGet>(Node) != nullptr)
|
|
405
|
+
{
|
|
406
|
+
for (UEdGraphPin* Pin : Node->Pins)
|
|
407
|
+
{
|
|
408
|
+
if (Pin->Direction == EGPD_Output && Pin->PinType.PinCategory != UEdGraphSchema_K2::PC_Exec)
|
|
409
|
+
{
|
|
410
|
+
UE_LOG(LogTemp, Display, TEXT(" - Found fallback data output pin: '%s'"), *Pin->PinName.ToString());
|
|
411
|
+
return Pin;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
UE_LOG(LogTemp, Warning, TEXT(" - No matching pin found for '%s'"), *PinName);
|
|
417
|
+
return nullptr;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Actor utilities
|
|
421
|
+
TSharedPtr<FJsonValue> FUnrealMCPCommonUtils::ActorToJson(AActor* Actor)
|
|
422
|
+
{
|
|
423
|
+
if (!Actor)
|
|
424
|
+
{
|
|
425
|
+
return MakeShared<FJsonValueNull>();
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
TSharedPtr<FJsonObject> ActorObject = MakeShared<FJsonObject>();
|
|
429
|
+
ActorObject->SetStringField(TEXT("name"), Actor->GetName());
|
|
430
|
+
ActorObject->SetStringField(TEXT("class"), Actor->GetClass()->GetName());
|
|
431
|
+
|
|
432
|
+
FVector Location = Actor->GetActorLocation();
|
|
433
|
+
TArray<TSharedPtr<FJsonValue>> LocationArray;
|
|
434
|
+
LocationArray.Add(MakeShared<FJsonValueNumber>(Location.X));
|
|
435
|
+
LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Y));
|
|
436
|
+
LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Z));
|
|
437
|
+
ActorObject->SetArrayField(TEXT("location"), LocationArray);
|
|
438
|
+
|
|
439
|
+
FRotator Rotation = Actor->GetActorRotation();
|
|
440
|
+
TArray<TSharedPtr<FJsonValue>> RotationArray;
|
|
441
|
+
RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Pitch));
|
|
442
|
+
RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Yaw));
|
|
443
|
+
RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Roll));
|
|
444
|
+
ActorObject->SetArrayField(TEXT("rotation"), RotationArray);
|
|
445
|
+
|
|
446
|
+
FVector Scale = Actor->GetActorScale3D();
|
|
447
|
+
TArray<TSharedPtr<FJsonValue>> ScaleArray;
|
|
448
|
+
ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.X));
|
|
449
|
+
ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Y));
|
|
450
|
+
ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Z));
|
|
451
|
+
ActorObject->SetArrayField(TEXT("scale"), ScaleArray);
|
|
452
|
+
|
|
453
|
+
return MakeShared<FJsonValueObject>(ActorObject);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
TSharedPtr<FJsonObject> FUnrealMCPCommonUtils::ActorToJsonObject(AActor* Actor, bool bDetailed)
|
|
457
|
+
{
|
|
458
|
+
if (!Actor)
|
|
459
|
+
{
|
|
460
|
+
return nullptr;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
TSharedPtr<FJsonObject> ActorObject = MakeShared<FJsonObject>();
|
|
464
|
+
ActorObject->SetStringField(TEXT("name"), Actor->GetName());
|
|
465
|
+
ActorObject->SetStringField(TEXT("class"), Actor->GetClass()->GetName());
|
|
466
|
+
|
|
467
|
+
FVector Location = Actor->GetActorLocation();
|
|
468
|
+
TArray<TSharedPtr<FJsonValue>> LocationArray;
|
|
469
|
+
LocationArray.Add(MakeShared<FJsonValueNumber>(Location.X));
|
|
470
|
+
LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Y));
|
|
471
|
+
LocationArray.Add(MakeShared<FJsonValueNumber>(Location.Z));
|
|
472
|
+
ActorObject->SetArrayField(TEXT("location"), LocationArray);
|
|
473
|
+
|
|
474
|
+
FRotator Rotation = Actor->GetActorRotation();
|
|
475
|
+
TArray<TSharedPtr<FJsonValue>> RotationArray;
|
|
476
|
+
RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Pitch));
|
|
477
|
+
RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Yaw));
|
|
478
|
+
RotationArray.Add(MakeShared<FJsonValueNumber>(Rotation.Roll));
|
|
479
|
+
ActorObject->SetArrayField(TEXT("rotation"), RotationArray);
|
|
480
|
+
|
|
481
|
+
FVector Scale = Actor->GetActorScale3D();
|
|
482
|
+
TArray<TSharedPtr<FJsonValue>> ScaleArray;
|
|
483
|
+
ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.X));
|
|
484
|
+
ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Y));
|
|
485
|
+
ScaleArray.Add(MakeShared<FJsonValueNumber>(Scale.Z));
|
|
486
|
+
ActorObject->SetArrayField(TEXT("scale"), ScaleArray);
|
|
487
|
+
|
|
488
|
+
return ActorObject;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
UK2Node_Event* FUnrealMCPCommonUtils::FindExistingEventNode(UEdGraph* Graph, const FString& EventName)
|
|
492
|
+
{
|
|
493
|
+
if (!Graph)
|
|
494
|
+
{
|
|
495
|
+
return nullptr;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Look for existing event nodes
|
|
499
|
+
for (UEdGraphNode* Node : Graph->Nodes)
|
|
500
|
+
{
|
|
501
|
+
UK2Node_Event* EventNode = Cast<UK2Node_Event>(Node);
|
|
502
|
+
if (EventNode && EventNode->EventReference.GetMemberName() == FName(*EventName))
|
|
503
|
+
{
|
|
504
|
+
UE_LOG(LogTemp, Display, TEXT("Found existing event node with name: %s"), *EventName);
|
|
505
|
+
return EventNode;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return nullptr;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
bool FUnrealMCPCommonUtils::SetObjectProperty(UObject* Object, const FString& PropertyName,
|
|
513
|
+
const TSharedPtr<FJsonValue>& Value, FString& OutErrorMessage)
|
|
514
|
+
{
|
|
515
|
+
if (!Object)
|
|
516
|
+
{
|
|
517
|
+
OutErrorMessage = TEXT("Invalid object");
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
FProperty* Property = Object->GetClass()->FindPropertyByName(*PropertyName);
|
|
522
|
+
if (!Property)
|
|
523
|
+
{
|
|
524
|
+
OutErrorMessage = FString::Printf(TEXT("Property not found: %s"), *PropertyName);
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
void* PropertyAddr = Property->ContainerPtrToValuePtr<void>(Object);
|
|
529
|
+
|
|
530
|
+
// Handle different property types
|
|
531
|
+
if (Property->IsA<FBoolProperty>())
|
|
532
|
+
{
|
|
533
|
+
((FBoolProperty*)Property)->SetPropertyValue(PropertyAddr, Value->AsBool());
|
|
534
|
+
return true;
|
|
535
|
+
}
|
|
536
|
+
else if (Property->IsA<FIntProperty>())
|
|
537
|
+
{
|
|
538
|
+
int32 IntValue = static_cast<int32>(Value->AsNumber());
|
|
539
|
+
FIntProperty* IntProperty = CastField<FIntProperty>(Property);
|
|
540
|
+
if (IntProperty)
|
|
541
|
+
{
|
|
542
|
+
IntProperty->SetPropertyValue_InContainer(Object, IntValue);
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
else if (Property->IsA<FFloatProperty>())
|
|
547
|
+
{
|
|
548
|
+
((FFloatProperty*)Property)->SetPropertyValue(PropertyAddr, Value->AsNumber());
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
else if (Property->IsA<FStrProperty>())
|
|
552
|
+
{
|
|
553
|
+
((FStrProperty*)Property)->SetPropertyValue(PropertyAddr, Value->AsString());
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
else if (Property->IsA<FByteProperty>())
|
|
557
|
+
{
|
|
558
|
+
FByteProperty* ByteProp = CastField<FByteProperty>(Property);
|
|
559
|
+
UEnum* EnumDef = ByteProp ? ByteProp->GetIntPropertyEnum() : nullptr;
|
|
560
|
+
|
|
561
|
+
// If this is a TEnumAsByte property (has associated enum)
|
|
562
|
+
if (EnumDef)
|
|
563
|
+
{
|
|
564
|
+
// Handle numeric value
|
|
565
|
+
if (Value->Type == EJson::Number)
|
|
566
|
+
{
|
|
567
|
+
uint8 ByteValue = static_cast<uint8>(Value->AsNumber());
|
|
568
|
+
ByteProp->SetPropertyValue(PropertyAddr, ByteValue);
|
|
569
|
+
|
|
570
|
+
UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric value: %d"),
|
|
571
|
+
*PropertyName, ByteValue);
|
|
572
|
+
return true;
|
|
573
|
+
}
|
|
574
|
+
// Handle string enum value
|
|
575
|
+
else if (Value->Type == EJson::String)
|
|
576
|
+
{
|
|
577
|
+
FString EnumValueName = Value->AsString();
|
|
578
|
+
|
|
579
|
+
// Try to convert numeric string to number first
|
|
580
|
+
if (EnumValueName.IsNumeric())
|
|
581
|
+
{
|
|
582
|
+
uint8 ByteValue = FCString::Atoi(*EnumValueName);
|
|
583
|
+
ByteProp->SetPropertyValue(PropertyAddr, ByteValue);
|
|
584
|
+
|
|
585
|
+
UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric string value: %s -> %d"),
|
|
586
|
+
*PropertyName, *EnumValueName, ByteValue);
|
|
587
|
+
return true;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Handle qualified enum names (e.g., "Player0" or "EAutoReceiveInput::Player0")
|
|
591
|
+
if (EnumValueName.Contains(TEXT("::")))
|
|
592
|
+
{
|
|
593
|
+
EnumValueName.Split(TEXT("::"), nullptr, &EnumValueName);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
int64 EnumValue = EnumDef->GetValueByNameString(EnumValueName);
|
|
597
|
+
if (EnumValue == INDEX_NONE)
|
|
598
|
+
{
|
|
599
|
+
// Try with full name as fallback
|
|
600
|
+
EnumValue = EnumDef->GetValueByNameString(Value->AsString());
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
if (EnumValue != INDEX_NONE)
|
|
604
|
+
{
|
|
605
|
+
ByteProp->SetPropertyValue(PropertyAddr, static_cast<uint8>(EnumValue));
|
|
606
|
+
|
|
607
|
+
UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to name value: %s -> %lld"),
|
|
608
|
+
*PropertyName, *EnumValueName, EnumValue);
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
else
|
|
612
|
+
{
|
|
613
|
+
// Log all possible enum values for debugging
|
|
614
|
+
UE_LOG(LogTemp, Warning, TEXT("Could not find enum value for '%s'. Available options:"), *EnumValueName);
|
|
615
|
+
for (int32 i = 0; i < EnumDef->NumEnums(); i++)
|
|
616
|
+
{
|
|
617
|
+
UE_LOG(LogTemp, Warning, TEXT(" - %s (value: %d)"),
|
|
618
|
+
*EnumDef->GetNameStringByIndex(i), EnumDef->GetValueByIndex(i));
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
OutErrorMessage = FString::Printf(TEXT("Could not find enum value for '%s'"), *EnumValueName);
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
else
|
|
627
|
+
{
|
|
628
|
+
// Regular byte property
|
|
629
|
+
uint8 ByteValue = static_cast<uint8>(Value->AsNumber());
|
|
630
|
+
ByteProp->SetPropertyValue(PropertyAddr, ByteValue);
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
else if (Property->IsA<FEnumProperty>())
|
|
635
|
+
{
|
|
636
|
+
FEnumProperty* EnumProp = CastField<FEnumProperty>(Property);
|
|
637
|
+
UEnum* EnumDef = EnumProp ? EnumProp->GetEnum() : nullptr;
|
|
638
|
+
FNumericProperty* UnderlyingNumericProp = EnumProp ? EnumProp->GetUnderlyingProperty() : nullptr;
|
|
639
|
+
|
|
640
|
+
if (EnumDef && UnderlyingNumericProp)
|
|
641
|
+
{
|
|
642
|
+
// Handle numeric value
|
|
643
|
+
if (Value->Type == EJson::Number)
|
|
644
|
+
{
|
|
645
|
+
int64 EnumValue = static_cast<int64>(Value->AsNumber());
|
|
646
|
+
UnderlyingNumericProp->SetIntPropertyValue(PropertyAddr, EnumValue);
|
|
647
|
+
|
|
648
|
+
UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric value: %lld"),
|
|
649
|
+
*PropertyName, EnumValue);
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
// Handle string enum value
|
|
653
|
+
else if (Value->Type == EJson::String)
|
|
654
|
+
{
|
|
655
|
+
FString EnumValueName = Value->AsString();
|
|
656
|
+
|
|
657
|
+
// Try to convert numeric string to number first
|
|
658
|
+
if (EnumValueName.IsNumeric())
|
|
659
|
+
{
|
|
660
|
+
int64 EnumValue = FCString::Atoi64(*EnumValueName);
|
|
661
|
+
UnderlyingNumericProp->SetIntPropertyValue(PropertyAddr, EnumValue);
|
|
662
|
+
|
|
663
|
+
UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to numeric string value: %s -> %lld"),
|
|
664
|
+
*PropertyName, *EnumValueName, EnumValue);
|
|
665
|
+
return true;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Handle qualified enum names
|
|
669
|
+
if (EnumValueName.Contains(TEXT("::")))
|
|
670
|
+
{
|
|
671
|
+
EnumValueName.Split(TEXT("::"), nullptr, &EnumValueName);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
int64 EnumValue = EnumDef->GetValueByNameString(EnumValueName);
|
|
675
|
+
if (EnumValue == INDEX_NONE)
|
|
676
|
+
{
|
|
677
|
+
// Try with full name as fallback
|
|
678
|
+
EnumValue = EnumDef->GetValueByNameString(Value->AsString());
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (EnumValue != INDEX_NONE)
|
|
682
|
+
{
|
|
683
|
+
UnderlyingNumericProp->SetIntPropertyValue(PropertyAddr, EnumValue);
|
|
684
|
+
|
|
685
|
+
UE_LOG(LogTemp, Display, TEXT("Setting enum property %s to name value: %s -> %lld"),
|
|
686
|
+
*PropertyName, *EnumValueName, EnumValue);
|
|
687
|
+
return true;
|
|
688
|
+
}
|
|
689
|
+
else
|
|
690
|
+
{
|
|
691
|
+
// Log all possible enum values for debugging
|
|
692
|
+
UE_LOG(LogTemp, Warning, TEXT("Could not find enum value for '%s'. Available options:"), *EnumValueName);
|
|
693
|
+
for (int32 i = 0; i < EnumDef->NumEnums(); i++)
|
|
694
|
+
{
|
|
695
|
+
UE_LOG(LogTemp, Warning, TEXT(" - %s (value: %d)"),
|
|
696
|
+
*EnumDef->GetNameStringByIndex(i), EnumDef->GetValueByIndex(i));
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
OutErrorMessage = FString::Printf(TEXT("Could not find enum value for '%s'"), *EnumValueName);
|
|
700
|
+
return false;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
OutErrorMessage = FString::Printf(TEXT("Unsupported property type: %s for property %s"),
|
|
707
|
+
*Property->GetClass()->GetName(), *PropertyName);
|
|
708
|
+
return false;
|
|
709
|
+
}
|