flockbay 0.10.15 → 0.10.17
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/codex/flockbayMcpStdioBridge.cjs +339 -0
- package/dist/codex/flockbayMcpStdioBridge.mjs +339 -0
- package/dist/{index--o4BPz5o.cjs → index-BxBuBx7C.cjs} +2706 -609
- package/dist/{index-CUp3juDS.mjs → index-CHm9r89K.mjs} +2707 -611
- package/dist/index.cjs +3 -5
- package/dist/index.mjs +3 -5
- package/dist/lib.cjs +7 -9
- package/dist/lib.d.cts +219 -531
- package/dist/lib.d.mts +219 -531
- package/dist/lib.mjs +7 -9
- package/dist/{runCodex-D3eT-TvB.cjs → runCodex-DuCGwO2K.cjs} +264 -43
- package/dist/{runCodex-o6PCbHQ7.mjs → runCodex-DudVDqNh.mjs} +263 -42
- package/dist/{runGemini-CBxZp6I7.cjs → runGemini-B25LZ4Cw.cjs} +64 -29
- package/dist/{runGemini-Bt0oEj_g.mjs → runGemini-Ddu8UCOS.mjs} +63 -28
- package/dist/{types-C-jnUdn_.cjs → types-CGQhv7Z-.cjs} +470 -1146
- package/dist/{types-DGd6ea2Z.mjs → types-DuhcLxar.mjs} +469 -1142
- package/package.json +1 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintCommands.cpp +195 -6
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPBlueprintNodeCommands.cpp +376 -5
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommandSchema.cpp +731 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPCommonUtils.cpp +476 -8
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/Commands/UnrealMCPEditorCommands.cpp +1518 -94
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/MCPServerRunnable.cpp +7 -4
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Private/UnrealMCPBridge.cpp +150 -112
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintCommands.h +2 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPBlueprintNodeCommands.h +4 -1
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPCommandSchema.h +42 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/Public/Commands/UnrealMCPEditorCommands.h +21 -0
- package/tools/unreal-mcp/upstream/MCPGameProject/Plugins/UnrealMCP/Source/UnrealMCP/UnrealMCP.Build.cs +4 -1
- package/dist/flockbayScreenshotGate-DJX3Is5d.mjs +0 -136
- package/dist/flockbayScreenshotGate-DkxU24cR.cjs +0 -138
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
#include "Camera/CameraActor.h"
|
|
17
17
|
#include "Kismet/GameplayStatics.h"
|
|
18
18
|
#include "EdGraphSchema_K2.h"
|
|
19
|
+
#include "UObject/UObjectIterator.h"
|
|
20
|
+
#include "Kismet/BlueprintFunctionLibrary.h"
|
|
19
21
|
|
|
20
22
|
// Declare the log category
|
|
21
23
|
DEFINE_LOG_CATEGORY_STATIC(LogUnrealMCP, Log, All);
|
|
@@ -34,6 +36,10 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleCommand(const FSt
|
|
|
34
36
|
{
|
|
35
37
|
return HandleAddBlueprintGetSelfComponentReference(Params);
|
|
36
38
|
}
|
|
39
|
+
else if (CommandType == TEXT("add_blueprint_get_component_node"))
|
|
40
|
+
{
|
|
41
|
+
return HandleAddBlueprintGetComponentNode(Params);
|
|
42
|
+
}
|
|
37
43
|
else if (CommandType == TEXT("add_blueprint_event_node"))
|
|
38
44
|
{
|
|
39
45
|
return HandleAddBlueprintEvent(Params);
|
|
@@ -58,10 +64,77 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleCommand(const FSt
|
|
|
58
64
|
{
|
|
59
65
|
return HandleFindBlueprintNodes(Params);
|
|
60
66
|
}
|
|
67
|
+
else if (CommandType == TEXT("search_blueprint_functions"))
|
|
68
|
+
{
|
|
69
|
+
return HandleSearchBlueprintFunctions(Params);
|
|
70
|
+
}
|
|
71
|
+
else if (CommandType == TEXT("resolve_blueprint_function"))
|
|
72
|
+
{
|
|
73
|
+
return HandleResolveBlueprintFunction(Params);
|
|
74
|
+
}
|
|
61
75
|
|
|
62
76
|
return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Unknown blueprint node command: %s"), *CommandType));
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintGetComponentNode(const TSharedPtr<FJsonObject>& Params)
|
|
80
|
+
{
|
|
81
|
+
// This mirrors the editor UX of dragging a Blueprint component into the EventGraph,
|
|
82
|
+
// which creates a variable-get node referencing that component on Self.
|
|
83
|
+
FString BlueprintName;
|
|
84
|
+
if (!Params->TryGetStringField(TEXT("blueprint_name"), BlueprintName))
|
|
85
|
+
{
|
|
86
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'blueprint_name' parameter"));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
FString ComponentName;
|
|
90
|
+
if (!Params->TryGetStringField(TEXT("component_name"), ComponentName))
|
|
91
|
+
{
|
|
92
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'component_name' parameter"));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
FVector2D NodePosition(0.0f, 0.0f);
|
|
96
|
+
if (Params->HasField(TEXT("node_position")))
|
|
97
|
+
{
|
|
98
|
+
NodePosition = FUnrealMCPCommonUtils::GetVector2DFromJson(Params, TEXT("node_position"));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
|
|
102
|
+
if (!Blueprint)
|
|
103
|
+
{
|
|
104
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(FString::Printf(TEXT("Blueprint not found: %s"), *BlueprintName));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
UEdGraph* EventGraph = FUnrealMCPCommonUtils::FindOrCreateEventGraph(Blueprint);
|
|
108
|
+
if (!EventGraph)
|
|
109
|
+
{
|
|
110
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to get event graph"));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
UK2Node_VariableGet* GetComponentNode = NewObject<UK2Node_VariableGet>(EventGraph);
|
|
114
|
+
if (!GetComponentNode)
|
|
115
|
+
{
|
|
116
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Failed to create get component node"));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
FMemberReference& VarRef = GetComponentNode->VariableReference;
|
|
120
|
+
VarRef.SetSelfMember(FName(*ComponentName));
|
|
121
|
+
|
|
122
|
+
GetComponentNode->NodePosX = NodePosition.X;
|
|
123
|
+
GetComponentNode->NodePosY = NodePosition.Y;
|
|
124
|
+
|
|
125
|
+
EventGraph->AddNode(GetComponentNode);
|
|
126
|
+
GetComponentNode->CreateNewGuid();
|
|
127
|
+
GetComponentNode->PostPlacedNewNode();
|
|
128
|
+
GetComponentNode->AllocateDefaultPins();
|
|
129
|
+
GetComponentNode->ReconstructNode();
|
|
130
|
+
|
|
131
|
+
FBlueprintEditorUtils::MarkBlueprintAsModified(Blueprint);
|
|
132
|
+
|
|
133
|
+
TSharedPtr<FJsonObject> ResultObj = MakeShared<FJsonObject>();
|
|
134
|
+
ResultObj->SetStringField(TEXT("node_id"), GetComponentNode->NodeGuid.ToString());
|
|
135
|
+
return ResultObj;
|
|
136
|
+
}
|
|
137
|
+
|
|
65
138
|
TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleConnectBlueprintNodes(const TSharedPtr<FJsonObject>& Params)
|
|
66
139
|
{
|
|
67
140
|
// Get required parameters
|
|
@@ -291,6 +364,11 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
291
364
|
FString Target;
|
|
292
365
|
Params->TryGetStringField(TEXT("target"), Target);
|
|
293
366
|
|
|
367
|
+
FString OwnerPath;
|
|
368
|
+
Params->TryGetStringField(TEXT("function_owner_path"), OwnerPath);
|
|
369
|
+
Params->TryGetStringField(TEXT("owner_class_path"), OwnerPath);
|
|
370
|
+
Params->TryGetStringField(TEXT("ownerPath"), OwnerPath);
|
|
371
|
+
|
|
294
372
|
// Find the blueprint
|
|
295
373
|
UBlueprint* Blueprint = FUnrealMCPCommonUtils::FindBlueprint(BlueprintName);
|
|
296
374
|
if (!Blueprint)
|
|
@@ -313,6 +391,21 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
313
391
|
UE_LOG(LogTemp, Display, TEXT("Looking for function '%s' in target '%s'"),
|
|
314
392
|
*FunctionName, Target.IsEmpty() ? TEXT("Blueprint") : *Target);
|
|
315
393
|
|
|
394
|
+
// If we have an explicit owner class path, resolve it first (most reliable across UE versions).
|
|
395
|
+
if (!OwnerPath.IsEmpty())
|
|
396
|
+
{
|
|
397
|
+
OwnerPath = OwnerPath.TrimStartAndEnd();
|
|
398
|
+
UClass* OwnerClass = LoadObject<UClass>(nullptr, *OwnerPath);
|
|
399
|
+
if (!OwnerClass && !OwnerPath.Contains(TEXT("'")))
|
|
400
|
+
{
|
|
401
|
+
OwnerClass = LoadObject<UClass>(nullptr, *FString::Printf(TEXT("Class'%s'"), *OwnerPath));
|
|
402
|
+
}
|
|
403
|
+
if (OwnerClass)
|
|
404
|
+
{
|
|
405
|
+
Function = OwnerClass->FindFunctionByName(*FunctionName);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
316
409
|
// Check if we have a target class specified
|
|
317
410
|
if (!Target.IsEmpty())
|
|
318
411
|
{
|
|
@@ -366,8 +459,8 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
366
459
|
}
|
|
367
460
|
}
|
|
368
461
|
|
|
369
|
-
// If we found a target class, look for the function there
|
|
370
|
-
if (TargetClass)
|
|
462
|
+
// If we found a target class, look for the function there (unless owner path already resolved).
|
|
463
|
+
if (TargetClass && !Function)
|
|
371
464
|
{
|
|
372
465
|
UE_LOG(LogTemp, Display, TEXT("Looking for function '%s' in class '%s'"),
|
|
373
466
|
*FunctionName, *TargetClass->GetName());
|
|
@@ -390,8 +483,6 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
390
483
|
for (TFieldIterator<UFunction> FuncIt(CurrentClass); FuncIt; ++FuncIt)
|
|
391
484
|
{
|
|
392
485
|
UFunction* AvailableFunc = *FuncIt;
|
|
393
|
-
UE_LOG(LogTemp, Display, TEXT(" - Available function: %s"), *AvailableFunc->GetName());
|
|
394
|
-
|
|
395
486
|
if (AvailableFunc->GetName().Equals(FunctionName, ESearchCase::IgnoreCase))
|
|
396
487
|
{
|
|
397
488
|
UE_LOG(LogTemp, Display, TEXT(" - Found case-insensitive match: %s"), *AvailableFunc->GetName());
|
|
@@ -670,6 +761,264 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintFunct
|
|
|
670
761
|
return ResultObj;
|
|
671
762
|
}
|
|
672
763
|
|
|
764
|
+
static bool IsBlueprintCallableFunction(UFunction* Function)
|
|
765
|
+
{
|
|
766
|
+
if (!Function) return false;
|
|
767
|
+
const bool bCallable = Function->HasAnyFunctionFlags(FUNC_BlueprintCallable | FUNC_BlueprintPure);
|
|
768
|
+
if (!bCallable) return false;
|
|
769
|
+
if (Function->HasAnyFunctionFlags(FUNC_Delegate)) return false;
|
|
770
|
+
if (Function->HasMetaData(FName(TEXT("DeprecatedFunction")))) return false;
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
static FString SafeDisplayName(UFunction* Function)
|
|
775
|
+
{
|
|
776
|
+
if (!Function) return TEXT("");
|
|
777
|
+
if (Function->HasMetaData(FName(TEXT("DisplayName"))))
|
|
778
|
+
{
|
|
779
|
+
return Function->GetMetaData(FName(TEXT("DisplayName")));
|
|
780
|
+
}
|
|
781
|
+
return Function->GetName();
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
static bool MatchesQuery(const FString& QueryLower, const FString& Candidate)
|
|
785
|
+
{
|
|
786
|
+
return Candidate.ToLower().Contains(QueryLower);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
static UClass* ResolveClassBestEffort(const FString& Target)
|
|
790
|
+
{
|
|
791
|
+
FString T = Target.TrimStartAndEnd();
|
|
792
|
+
if (T.IsEmpty()) return nullptr;
|
|
793
|
+
|
|
794
|
+
if (T.StartsWith(TEXT("/Script/")))
|
|
795
|
+
{
|
|
796
|
+
return LoadObject<UClass>(nullptr, *T);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
UClass* Found = FindObject<UClass>(ANY_PACKAGE, *T);
|
|
800
|
+
if (!Found && !T.StartsWith(TEXT("U")))
|
|
801
|
+
{
|
|
802
|
+
Found = FindObject<UClass>(ANY_PACKAGE, *(FString(TEXT("U")) + T));
|
|
803
|
+
}
|
|
804
|
+
if (!Found && !T.EndsWith(TEXT("Library")))
|
|
805
|
+
{
|
|
806
|
+
Found = FindObject<UClass>(ANY_PACKAGE, *(FString(TEXT("U")) + T + TEXT("Library")));
|
|
807
|
+
}
|
|
808
|
+
if (!Found && !T.EndsWith(TEXT("Component")))
|
|
809
|
+
{
|
|
810
|
+
Found = FindObject<UClass>(ANY_PACKAGE, *(FString(TEXT("U")) + T + TEXT("Component")));
|
|
811
|
+
}
|
|
812
|
+
return Found;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleSearchBlueprintFunctions(const TSharedPtr<FJsonObject>& Params)
|
|
816
|
+
{
|
|
817
|
+
FString Query;
|
|
818
|
+
if (!Params->TryGetStringField(TEXT("query"), Query) && !Params->TryGetStringField(TEXT("name"), Query))
|
|
819
|
+
{
|
|
820
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'query' parameter"));
|
|
821
|
+
}
|
|
822
|
+
Query = Query.TrimStartAndEnd();
|
|
823
|
+
if (Query.IsEmpty())
|
|
824
|
+
{
|
|
825
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("'query' is empty"));
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
FString Target;
|
|
829
|
+
Params->TryGetStringField(TEXT("target"), Target);
|
|
830
|
+
Params->TryGetStringField(TEXT("class"), Target);
|
|
831
|
+
|
|
832
|
+
int32 Limit = 25;
|
|
833
|
+
if (Params->HasField(TEXT("limit")))
|
|
834
|
+
{
|
|
835
|
+
Limit = (int32)Params->GetNumberField(TEXT("limit"));
|
|
836
|
+
Limit = FMath::Clamp(Limit, 1, 200);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
UClass* TargetClass = nullptr;
|
|
840
|
+
if (!Target.IsEmpty())
|
|
841
|
+
{
|
|
842
|
+
TargetClass = ResolveClassBestEffort(Target);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const FString QueryLower = Query.ToLower();
|
|
846
|
+
TArray<TSharedPtr<FJsonValue>> Matches;
|
|
847
|
+
|
|
848
|
+
auto MaybeAddFunction = [&](UFunction* Function, UClass* OwnerClass)
|
|
849
|
+
{
|
|
850
|
+
if ((int32)Matches.Num() >= Limit) return;
|
|
851
|
+
if (!IsBlueprintCallableFunction(Function)) return;
|
|
852
|
+
|
|
853
|
+
const FString Name = Function->GetName();
|
|
854
|
+
const FString Display = SafeDisplayName(Function);
|
|
855
|
+
if (!MatchesQuery(QueryLower, Name) && !MatchesQuery(QueryLower, Display)) return;
|
|
856
|
+
|
|
857
|
+
TSharedPtr<FJsonObject> Obj = MakeShared<FJsonObject>();
|
|
858
|
+
Obj->SetStringField(TEXT("functionName"), Name);
|
|
859
|
+
Obj->SetStringField(TEXT("displayName"), Display);
|
|
860
|
+
if (OwnerClass)
|
|
861
|
+
{
|
|
862
|
+
Obj->SetStringField(TEXT("ownerClass"), OwnerClass->GetName());
|
|
863
|
+
Obj->SetStringField(TEXT("ownerPath"), OwnerClass->GetPathName());
|
|
864
|
+
}
|
|
865
|
+
Obj->SetBoolField(TEXT("isStatic"), Function->HasAnyFunctionFlags(FUNC_Static));
|
|
866
|
+
|
|
867
|
+
// Minimal signature info.
|
|
868
|
+
TArray<TSharedPtr<FJsonValue>> Inputs;
|
|
869
|
+
TArray<TSharedPtr<FJsonValue>> Outputs;
|
|
870
|
+
for (TFieldIterator<FProperty> It(Function); It; ++It)
|
|
871
|
+
{
|
|
872
|
+
FProperty* Prop = *It;
|
|
873
|
+
if (!Prop) continue;
|
|
874
|
+
const bool bIsReturn = Prop->HasAnyPropertyFlags(CPF_ReturnParm);
|
|
875
|
+
const bool bIsOut = Prop->HasAnyPropertyFlags(CPF_OutParm) && !Prop->HasAnyPropertyFlags(CPF_ConstParm);
|
|
876
|
+
|
|
877
|
+
TSharedPtr<FJsonObject> P = MakeShared<FJsonObject>();
|
|
878
|
+
P->SetStringField(TEXT("name"), Prop->GetName());
|
|
879
|
+
P->SetStringField(TEXT("type"), Prop->GetCPPType());
|
|
880
|
+
|
|
881
|
+
if (bIsReturn || bIsOut)
|
|
882
|
+
{
|
|
883
|
+
Outputs.Add(MakeShared<FJsonValueObject>(P));
|
|
884
|
+
}
|
|
885
|
+
else
|
|
886
|
+
{
|
|
887
|
+
Inputs.Add(MakeShared<FJsonValueObject>(P));
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
Obj->SetArrayField(TEXT("inputs"), Inputs);
|
|
891
|
+
Obj->SetArrayField(TEXT("outputs"), Outputs);
|
|
892
|
+
|
|
893
|
+
Matches.Add(MakeShared<FJsonValueObject>(Obj));
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
if (TargetClass)
|
|
897
|
+
{
|
|
898
|
+
for (TFieldIterator<UFunction> FuncIt(TargetClass, EFieldIteratorFlags::IncludeSuper); FuncIt; ++FuncIt)
|
|
899
|
+
{
|
|
900
|
+
MaybeAddFunction(*FuncIt, TargetClass);
|
|
901
|
+
if ((int32)Matches.Num() >= Limit) break;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
else
|
|
905
|
+
{
|
|
906
|
+
for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
|
|
907
|
+
{
|
|
908
|
+
UClass* Class = *ClassIt;
|
|
909
|
+
if (!Class) continue;
|
|
910
|
+
if (!Class->IsChildOf(UBlueprintFunctionLibrary::StaticClass())) continue;
|
|
911
|
+
if (Class->HasAnyClassFlags(CLASS_Deprecated)) continue;
|
|
912
|
+
|
|
913
|
+
for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
|
|
914
|
+
{
|
|
915
|
+
MaybeAddFunction(*FuncIt, Class);
|
|
916
|
+
if ((int32)Matches.Num() >= Limit) break;
|
|
917
|
+
}
|
|
918
|
+
if ((int32)Matches.Num() >= Limit) break;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
|
|
923
|
+
Result->SetStringField(TEXT("query"), Query);
|
|
924
|
+
if (!Target.IsEmpty()) Result->SetStringField(TEXT("target"), Target);
|
|
925
|
+
Result->SetNumberField(TEXT("count"), Matches.Num());
|
|
926
|
+
Result->SetArrayField(TEXT("matches"), Matches);
|
|
927
|
+
return Result;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleResolveBlueprintFunction(const TSharedPtr<FJsonObject>& Params)
|
|
931
|
+
{
|
|
932
|
+
FString FunctionName;
|
|
933
|
+
if (!Params->TryGetStringField(TEXT("function_name"), FunctionName) &&
|
|
934
|
+
!Params->TryGetStringField(TEXT("name"), FunctionName) &&
|
|
935
|
+
!Params->TryGetStringField(TEXT("query"), FunctionName))
|
|
936
|
+
{
|
|
937
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'function_name' parameter"));
|
|
938
|
+
}
|
|
939
|
+
FunctionName = FunctionName.TrimStartAndEnd();
|
|
940
|
+
if (FunctionName.IsEmpty())
|
|
941
|
+
{
|
|
942
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("'function_name' is empty"));
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
FString Target;
|
|
946
|
+
Params->TryGetStringField(TEXT("target"), Target);
|
|
947
|
+
Params->TryGetStringField(TEXT("class"), Target);
|
|
948
|
+
|
|
949
|
+
UClass* TargetClass = nullptr;
|
|
950
|
+
if (!Target.IsEmpty())
|
|
951
|
+
{
|
|
952
|
+
TargetClass = ResolveClassBestEffort(Target);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
UFunction* Resolved = nullptr;
|
|
956
|
+
UClass* Owner = nullptr;
|
|
957
|
+
|
|
958
|
+
auto SearchClass = [&](UClass* Class)
|
|
959
|
+
{
|
|
960
|
+
if (!Class || Resolved) return;
|
|
961
|
+
for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::IncludeSuper); FuncIt; ++FuncIt)
|
|
962
|
+
{
|
|
963
|
+
UFunction* F = *FuncIt;
|
|
964
|
+
if (!IsBlueprintCallableFunction(F)) continue;
|
|
965
|
+
if (F->GetName().Equals(FunctionName, ESearchCase::IgnoreCase))
|
|
966
|
+
{
|
|
967
|
+
Resolved = F;
|
|
968
|
+
Owner = Class;
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
if (TargetClass)
|
|
975
|
+
{
|
|
976
|
+
SearchClass(TargetClass);
|
|
977
|
+
}
|
|
978
|
+
else
|
|
979
|
+
{
|
|
980
|
+
// Prefer common Blueprint libraries first.
|
|
981
|
+
const TArray<FString> Preferred = { TEXT("KismetMathLibrary"), TEXT("KismetSystemLibrary"), TEXT("GameplayStatics") };
|
|
982
|
+
for (const FString& Name : Preferred)
|
|
983
|
+
{
|
|
984
|
+
if (Resolved) break;
|
|
985
|
+
SearchClass(ResolveClassBestEffort(Name));
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
if (!Resolved)
|
|
989
|
+
{
|
|
990
|
+
for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
|
|
991
|
+
{
|
|
992
|
+
UClass* Class = *ClassIt;
|
|
993
|
+
if (!Class) continue;
|
|
994
|
+
if (!Class->IsChildOf(UBlueprintFunctionLibrary::StaticClass())) continue;
|
|
995
|
+
SearchClass(Class);
|
|
996
|
+
if (Resolved) break;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
if (!Resolved || !Owner)
|
|
1002
|
+
{
|
|
1003
|
+
return FUnrealMCPCommonUtils::CreateErrorResponse(
|
|
1004
|
+
FString::Printf(TEXT("Function not found or not Blueprint-callable: %s"), *FunctionName));
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
TSharedPtr<FJsonObject> Result = MakeShared<FJsonObject>();
|
|
1008
|
+
Result->SetStringField(TEXT("functionName"), Resolved->GetName());
|
|
1009
|
+
Result->SetStringField(TEXT("displayName"), SafeDisplayName(Resolved));
|
|
1010
|
+
Result->SetStringField(TEXT("ownerClass"), Owner->GetName());
|
|
1011
|
+
Result->SetStringField(TEXT("ownerPath"), Owner->GetPathName());
|
|
1012
|
+
|
|
1013
|
+
// Suggest params for add_blueprint_function_node (caller must add blueprint_name).
|
|
1014
|
+
TSharedPtr<FJsonObject> Suggested = MakeShared<FJsonObject>();
|
|
1015
|
+
Suggested->SetStringField(TEXT("function_name"), Resolved->GetName());
|
|
1016
|
+
Suggested->SetStringField(TEXT("function_owner_path"), Owner->GetPathName());
|
|
1017
|
+
Result->SetObjectField(TEXT("suggested"), Suggested);
|
|
1018
|
+
|
|
1019
|
+
return Result;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
673
1022
|
TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintVariable(const TSharedPtr<FJsonObject>& Params)
|
|
674
1023
|
{
|
|
675
1024
|
// Get required parameters
|
|
@@ -690,6 +1039,28 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleAddBlueprintVaria
|
|
|
690
1039
|
{
|
|
691
1040
|
return FUnrealMCPCommonUtils::CreateErrorResponse(TEXT("Missing 'variable_type' parameter"));
|
|
692
1041
|
}
|
|
1042
|
+
VariableType = VariableType.TrimStartAndEnd();
|
|
1043
|
+
const FString VariableTypeLower = VariableType.ToLower();
|
|
1044
|
+
if (VariableTypeLower == TEXT("bool") || VariableTypeLower == TEXT("boolean"))
|
|
1045
|
+
{
|
|
1046
|
+
VariableType = TEXT("Boolean");
|
|
1047
|
+
}
|
|
1048
|
+
else if (VariableTypeLower == TEXT("int") || VariableTypeLower == TEXT("integer"))
|
|
1049
|
+
{
|
|
1050
|
+
VariableType = TEXT("Integer");
|
|
1051
|
+
}
|
|
1052
|
+
else if (VariableTypeLower == TEXT("float") || VariableTypeLower == TEXT("number") || VariableTypeLower == TEXT("double"))
|
|
1053
|
+
{
|
|
1054
|
+
VariableType = TEXT("Float");
|
|
1055
|
+
}
|
|
1056
|
+
else if (VariableTypeLower == TEXT("string") || VariableTypeLower == TEXT("str"))
|
|
1057
|
+
{
|
|
1058
|
+
VariableType = TEXT("String");
|
|
1059
|
+
}
|
|
1060
|
+
else if (VariableTypeLower == TEXT("vector") || VariableTypeLower == TEXT("vec3"))
|
|
1061
|
+
{
|
|
1062
|
+
VariableType = TEXT("Vector");
|
|
1063
|
+
}
|
|
693
1064
|
|
|
694
1065
|
// Get optional parameters
|
|
695
1066
|
bool IsExposed = false;
|
|
@@ -921,4 +1292,4 @@ TSharedPtr<FJsonObject> FUnrealMCPBlueprintNodeCommands::HandleFindBlueprintNode
|
|
|
921
1292
|
ResultObj->SetArrayField(TEXT("node_guids"), NodeGuidArray);
|
|
922
1293
|
|
|
923
1294
|
return ResultObj;
|
|
924
|
-
}
|
|
1295
|
+
}
|