Create MCPUtils
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "BlueprintMCPServer.h"
|
||||
#include "MCPUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "EdGraph/EdGraph.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
@@ -47,19 +48,19 @@ void FBlueprintMCPServer::HandleCreateAnimBlueprint(const FJsonObject* Json, FJs
|
||||
|
||||
if (Name.IsEmpty() || PackagePath.IsEmpty() || SkeletonName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: name, packagePath, skeleton"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: name, packagePath, skeleton"));
|
||||
}
|
||||
|
||||
if (!PackagePath.StartsWith(TEXT("/Game")))
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("packagePath must start with '/Game'"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("packagePath must start with '/Game'"));
|
||||
}
|
||||
|
||||
// Check if asset already exists
|
||||
FString FullAssetPath = PackagePath / Name;
|
||||
if (FindBlueprintAsset(Name) || FindBlueprintAsset(FullAssetPath))
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||
TEXT("Blueprint '%s' already exists. Use a different name or delete the existing asset first."),
|
||||
*Name));
|
||||
}
|
||||
@@ -114,7 +115,7 @@ void FBlueprintMCPServer::HandleCreateAnimBlueprint(const FJsonObject* Json, FJs
|
||||
|
||||
if (!Skeleton)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||
TEXT("Skeleton '%s' not found. Provide the skeleton asset name or path. Use '__create_test_skeleton__' for testing."),
|
||||
*SkeletonName));
|
||||
}
|
||||
@@ -141,7 +142,7 @@ void FBlueprintMCPServer::HandleCreateAnimBlueprint(const FJsonObject* Json, FJs
|
||||
UPackage* Package = CreatePackage(*FullPackagePath);
|
||||
if (!Package)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("Failed to create package at '%s'"), *FullPackagePath));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Failed to create package at '%s'"), *FullPackagePath));
|
||||
}
|
||||
|
||||
// Create the Animation Blueprint
|
||||
@@ -157,7 +158,7 @@ void FBlueprintMCPServer::HandleCreateAnimBlueprint(const FJsonObject* Json, FJs
|
||||
|
||||
if (!NewAnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("FKismetEditorUtilities::CreateBlueprint returned null for AnimBlueprint"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("FKismetEditorUtilities::CreateBlueprint returned null for AnimBlueprint"));
|
||||
}
|
||||
|
||||
// Set target skeleton
|
||||
@@ -167,7 +168,7 @@ void FBlueprintMCPServer::HandleCreateAnimBlueprint(const FJsonObject* Json, FJs
|
||||
FKismetEditorUtilities::CompileBlueprint(NewAnimBP);
|
||||
|
||||
// Save
|
||||
bool bSaved = SaveBlueprintPackage(NewAnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(NewAnimBP);
|
||||
|
||||
// Refresh asset cache
|
||||
FAssetRegistryModule& ARM = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
||||
@@ -204,61 +205,6 @@ void FBlueprintMCPServer::HandleCreateAnimBlueprint(const FJsonObject* Json, FJs
|
||||
// Tier 2: State Machine Mutation
|
||||
// ============================================================
|
||||
|
||||
// Helper: find a state machine graph by name within an AnimBlueprint
|
||||
static UAnimationStateMachineGraph* FindStateMachineGraph(UBlueprint* BP, const FString& GraphName)
|
||||
{
|
||||
TArray<UEdGraph*> AllGraphs;
|
||||
BP->GetAllGraphs(AllGraphs);
|
||||
for (UEdGraph* Graph : AllGraphs)
|
||||
{
|
||||
if (UAnimationStateMachineGraph* SMGraph = Cast<UAnimationStateMachineGraph>(Graph))
|
||||
{
|
||||
if (SMGraph->GetName() == GraphName)
|
||||
{
|
||||
return SMGraph;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Helper: find a state node by name within a state machine graph
|
||||
static UAnimStateNode* FindStateByName(UAnimationStateMachineGraph* SMGraph, const FString& StateName)
|
||||
{
|
||||
for (UEdGraphNode* Node : SMGraph->Nodes)
|
||||
{
|
||||
if (UAnimStateNode* StateNode = Cast<UAnimStateNode>(Node))
|
||||
{
|
||||
if (StateNode->GetStateName() == StateName)
|
||||
{
|
||||
return StateNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Helper: find a transition between two states
|
||||
static UAnimStateTransitionNode* FindTransition(UAnimationStateMachineGraph* SMGraph,
|
||||
const FString& FromStateName, const FString& ToStateName)
|
||||
{
|
||||
for (UEdGraphNode* Node : SMGraph->Nodes)
|
||||
{
|
||||
if (UAnimStateTransitionNode* TransNode = Cast<UAnimStateTransitionNode>(Node))
|
||||
{
|
||||
UAnimStateNode* FromState = Cast<UAnimStateNode>(TransNode->GetPreviousState());
|
||||
UAnimStateNode* ToState = Cast<UAnimStateNode>(TransNode->GetNextState());
|
||||
if (FromState && ToState &&
|
||||
FromState->GetStateName() == FromStateName &&
|
||||
ToState->GetStateName() == ToStateName)
|
||||
{
|
||||
return TransNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FBlueprintMCPServer::HandleAddAnimState(const FJsonObject* Json, FJsonObject* Result)
|
||||
{
|
||||
FString BlueprintName = Json->GetStringField(TEXT("blueprint"));
|
||||
@@ -267,32 +213,32 @@ void FBlueprintMCPServer::HandleAddAnimState(const FJsonObject* Json, FJsonObjec
|
||||
|
||||
if (BlueprintName.IsEmpty() || GraphName.IsEmpty() || StateName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = FindStateMachineGraph(BP, GraphName);
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(BP, GraphName);
|
||||
if (!SMGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
// Check for duplicate state name
|
||||
if (FindStateByName(SMGraph, StateName))
|
||||
if (MCPUtils::FindStateByName(SMGraph, StateName))
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State '%s' already exists in graph '%s'"), *StateName, *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State '%s' already exists in graph '%s'"), *StateName, *GraphName));
|
||||
}
|
||||
|
||||
// Get position
|
||||
@@ -352,7 +298,7 @@ void FBlueprintMCPServer::HandleAddAnimState(const FJsonObject* Json, FJsonObjec
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("stateName"), StateName);
|
||||
@@ -369,32 +315,32 @@ void FBlueprintMCPServer::HandleRemoveAnimState(const FJsonObject* Json, FJsonOb
|
||||
|
||||
if (BlueprintName.IsEmpty() || GraphName.IsEmpty() || StateName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = FindStateMachineGraph(BP, GraphName);
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(BP, GraphName);
|
||||
if (!SMGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
UAnimStateNode* StateNode = FindStateByName(SMGraph, StateName);
|
||||
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName);
|
||||
if (!StateNode)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State '%s' not found in graph '%s'"), *StateName, *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State '%s' not found in graph '%s'"), *StateName, *GraphName));
|
||||
}
|
||||
|
||||
// Collect and remove transitions connected to this state
|
||||
@@ -423,7 +369,7 @@ void FBlueprintMCPServer::HandleRemoveAnimState(const FJsonObject* Json, FJsonOb
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("removedState"), StateName);
|
||||
@@ -440,38 +386,38 @@ void FBlueprintMCPServer::HandleAddAnimTransition(const FJsonObject* Json, FJson
|
||||
|
||||
if (BlueprintName.IsEmpty() || GraphName.IsEmpty() || FromStateName.IsEmpty() || ToStateName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, fromState, toState"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, fromState, toState"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = FindStateMachineGraph(BP, GraphName);
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(BP, GraphName);
|
||||
if (!SMGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
UAnimStateNode* FromState = FindStateByName(SMGraph, FromStateName);
|
||||
UAnimStateNode* FromState = MCPUtils::FindStateByName(SMGraph, FromStateName);
|
||||
if (!FromState)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("From state '%s' not found"), *FromStateName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("From state '%s' not found"), *FromStateName));
|
||||
}
|
||||
|
||||
UAnimStateNode* ToState = FindStateByName(SMGraph, ToStateName);
|
||||
UAnimStateNode* ToState = MCPUtils::FindStateByName(SMGraph, ToStateName);
|
||||
if (!ToState)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("To state '%s' not found"), *ToStateName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("To state '%s' not found"), *ToStateName));
|
||||
}
|
||||
|
||||
// Create transition node
|
||||
@@ -506,7 +452,7 @@ void FBlueprintMCPServer::HandleAddAnimTransition(const FJsonObject* Json, FJson
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("fromState"), FromStateName);
|
||||
@@ -527,32 +473,32 @@ void FBlueprintMCPServer::HandleSetTransitionRule(const FJsonObject* Json, FJson
|
||||
|
||||
if (BlueprintName.IsEmpty() || GraphName.IsEmpty() || FromStateName.IsEmpty() || ToStateName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, fromState, toState"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, fromState, toState"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = FindStateMachineGraph(BP, GraphName);
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(BP, GraphName);
|
||||
if (!SMGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
UAnimStateTransitionNode* TransNode = FindTransition(SMGraph, FromStateName, ToStateName);
|
||||
UAnimStateTransitionNode* TransNode = MCPUtils::FindTransition(SMGraph, FromStateName, ToStateName);
|
||||
if (!TransNode)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||
TEXT("Transition from '%s' to '%s' not found in graph '%s'"),
|
||||
*FromStateName, *ToStateName, *GraphName));
|
||||
}
|
||||
@@ -588,12 +534,12 @@ void FBlueprintMCPServer::HandleSetTransitionRule(const FJsonObject* Json, FJson
|
||||
|
||||
if (ChangedCount == 0)
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("No properties to update. Provide at least one of: crossfadeDuration, blendMode, priorityOrder, logicType, bBidirectional"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("No properties to update. Provide at least one of: crossfadeDuration, blendMode, priorityOrder, logicType, bBidirectional"));
|
||||
}
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("fromState"), FromStateName);
|
||||
@@ -619,20 +565,20 @@ void FBlueprintMCPServer::HandleAddAnimNode(const FJsonObject* Json, FJsonObject
|
||||
|
||||
if (BlueprintName.IsEmpty() || NodeType.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, nodeType"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, nodeType"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
// Find target graph (default to AnimGraph if not specified)
|
||||
@@ -655,7 +601,7 @@ void FBlueprintMCPServer::HandleAddAnimNode(const FJsonObject* Json, FJsonObject
|
||||
|
||||
if (!TargetGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("Graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
int32 PosX = Json->HasField(TEXT("posX")) ? (int32)Json->GetNumberField(TEXT("posX")) : 0;
|
||||
@@ -735,14 +681,14 @@ void FBlueprintMCPServer::HandleAddAnimNode(const FJsonObject* Json, FJsonObject
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||
TEXT("Unsupported nodeType '%s'. Supported: SequencePlayer, BlendSpacePlayer, StateMachine"),
|
||||
*NodeType));
|
||||
}
|
||||
|
||||
if (!NewNode)
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Failed to create anim node"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Failed to create anim node"));
|
||||
}
|
||||
|
||||
NewNode->NodePosX = PosX;
|
||||
@@ -752,7 +698,7 @@ void FBlueprintMCPServer::HandleAddAnimNode(const FJsonObject* Json, FJsonObject
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("nodeType"), NodeType);
|
||||
@@ -784,7 +730,7 @@ void FBlueprintMCPServer::HandleAddStateMachine(const FJsonObject* Json, FJsonOb
|
||||
|
||||
if (BlueprintName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||
}
|
||||
|
||||
// Default name
|
||||
@@ -815,38 +761,38 @@ void FBlueprintMCPServer::HandleSetStateAnimation(const FJsonObject* Json, FJson
|
||||
|
||||
if (BlueprintName.IsEmpty() || GraphName.IsEmpty() || StateName.IsEmpty() || AnimAssetName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName, animationAsset"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName, animationAsset"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = FindStateMachineGraph(BP, GraphName);
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(BP, GraphName);
|
||||
if (!SMGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
UAnimStateNode* StateNode = FindStateByName(SMGraph, StateName);
|
||||
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName);
|
||||
if (!StateNode)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State '%s' not found in graph '%s'"), *StateName, *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State '%s' not found in graph '%s'"), *StateName, *GraphName));
|
||||
}
|
||||
|
||||
UEdGraph* InnerGraph = StateNode->GetBoundGraph();
|
||||
if (!InnerGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State '%s' has no bound graph"), *StateName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State '%s' has no bound graph"), *StateName));
|
||||
}
|
||||
|
||||
// Find the animation asset
|
||||
@@ -866,7 +812,7 @@ void FBlueprintMCPServer::HandleSetStateAnimation(const FJsonObject* Json, FJson
|
||||
|
||||
if (!AnimSeq)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("Animation asset '%s' not found"), *AnimAssetName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Animation asset '%s' not found"), *AnimAssetName));
|
||||
}
|
||||
|
||||
// Find existing SequencePlayer or create one
|
||||
@@ -894,7 +840,7 @@ void FBlueprintMCPServer::HandleSetStateAnimation(const FJsonObject* Json, FJson
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("stateName"), StateName);
|
||||
@@ -908,20 +854,20 @@ void FBlueprintMCPServer::HandleListAnimSlots(const FJsonObject* Json, FJsonObje
|
||||
FString BlueprintName = Json->GetStringField(TEXT("blueprint"));
|
||||
if (BlueprintName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
// Walk all anim nodes to collect slot names
|
||||
@@ -967,20 +913,20 @@ void FBlueprintMCPServer::HandleListSyncGroups(const FJsonObject* Json, FJsonObj
|
||||
FString BlueprintName = Json->GetStringField(TEXT("blueprint"));
|
||||
if (BlueprintName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
// Walk all anim nodes to collect sync group names
|
||||
@@ -1033,12 +979,12 @@ void FBlueprintMCPServer::HandleCreateBlendSpace(const FJsonObject* Json, FJsonO
|
||||
|
||||
if (Name.IsEmpty() || PackagePath.IsEmpty() || SkeletonName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: name, packagePath, skeleton"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: name, packagePath, skeleton"));
|
||||
}
|
||||
|
||||
if (!PackagePath.StartsWith(TEXT("/Game")))
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("packagePath must start with '/Game'"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("packagePath must start with '/Game'"));
|
||||
}
|
||||
|
||||
// Check if asset already exists
|
||||
@@ -1051,7 +997,7 @@ void FBlueprintMCPServer::HandleCreateBlendSpace(const FJsonObject* Json, FJsonO
|
||||
{
|
||||
if (Asset.AssetName.ToString() == Name || Asset.GetObjectPathString() == FullAssetPath)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||
TEXT("Blend Space '%s' already exists. Use a different name or delete the existing asset first."),
|
||||
*Name));
|
||||
}
|
||||
@@ -1106,7 +1052,7 @@ void FBlueprintMCPServer::HandleCreateBlendSpace(const FJsonObject* Json, FJsonO
|
||||
|
||||
if (!Skeleton)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
||||
TEXT("Skeleton '%s' not found. Provide the skeleton asset name or path. Use '__create_test_skeleton__' for testing."),
|
||||
*SkeletonName));
|
||||
}
|
||||
@@ -1119,14 +1065,14 @@ void FBlueprintMCPServer::HandleCreateBlendSpace(const FJsonObject* Json, FJsonO
|
||||
UPackage* Package = CreatePackage(*FullPackagePath);
|
||||
if (!Package)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("Failed to create package at '%s'"), *FullPackagePath));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Failed to create package at '%s'"), *FullPackagePath));
|
||||
}
|
||||
|
||||
// Create the Blend Space
|
||||
UBlendSpace* NewBS = NewObject<UBlendSpace>(Package, FName(*Name), RF_Public | RF_Standalone);
|
||||
if (!NewBS)
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Failed to create Blend Space object"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Failed to create Blend Space object"));
|
||||
}
|
||||
|
||||
// Set skeleton
|
||||
@@ -1134,7 +1080,7 @@ void FBlueprintMCPServer::HandleCreateBlendSpace(const FJsonObject* Json, FJsonO
|
||||
|
||||
// Mark dirty and save
|
||||
NewBS->MarkPackageDirty();
|
||||
bool bSaved = SaveGenericPackage(NewBS);
|
||||
bool bSaved = MCPUtils::SaveGenericPackage(NewBS);
|
||||
|
||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Blend Space '%s' (saved: %s)"),
|
||||
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
||||
@@ -1154,7 +1100,7 @@ void FBlueprintMCPServer::HandleSetBlendSpaceSamples(const FJsonObject* Json, FJ
|
||||
FString BlendSpaceName = Json->GetStringField(TEXT("blendSpace"));
|
||||
if (BlendSpaceName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required field: blendSpace"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blendSpace"));
|
||||
}
|
||||
|
||||
// Load the blend space
|
||||
@@ -1190,7 +1136,7 @@ void FBlueprintMCPServer::HandleSetBlendSpaceSamples(const FJsonObject* Json, FJ
|
||||
|
||||
if (!BS)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("Blend Space '%s' not found"), *BlendSpaceName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Blend Space '%s' not found"), *BlendSpaceName));
|
||||
}
|
||||
|
||||
// Set axis parameters
|
||||
@@ -1288,7 +1234,7 @@ void FBlueprintMCPServer::HandleSetBlendSpaceSamples(const FJsonObject* Json, FJ
|
||||
|
||||
// Save
|
||||
BS->MarkPackageDirty();
|
||||
bool bSaved = SaveGenericPackage(BS);
|
||||
bool bSaved = MCPUtils::SaveGenericPackage(BS);
|
||||
|
||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set %d samples on Blend Space '%s' (saved: %s)"),
|
||||
SamplesSet, *BS->GetName(), bSaved ? TEXT("true") : TEXT("false"));
|
||||
@@ -1314,38 +1260,38 @@ void FBlueprintMCPServer::HandleSetStateBlendSpace(const FJsonObject* Json, FJso
|
||||
|
||||
if (BlueprintName.IsEmpty() || GraphName.IsEmpty() || StateName.IsEmpty() || BlendSpaceName.IsEmpty())
|
||||
{
|
||||
return MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName, blendSpace"));
|
||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required fields: blueprint, graph, stateName, blendSpace"));
|
||||
}
|
||||
|
||||
FString LoadError;
|
||||
UBlueprint* BP = LoadBlueprintByName(BlueprintName, LoadError);
|
||||
if (!BP)
|
||||
{
|
||||
return MakeErrorJson(Result, LoadError);
|
||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
||||
}
|
||||
|
||||
UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP);
|
||||
if (!AnimBP)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("'%s' is not an Animation Blueprint"), *BlueprintName));
|
||||
}
|
||||
|
||||
UAnimationStateMachineGraph* SMGraph = FindStateMachineGraph(BP, GraphName);
|
||||
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(BP, GraphName);
|
||||
if (!SMGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found"), *GraphName));
|
||||
}
|
||||
|
||||
UAnimStateNode* StateNode = FindStateByName(SMGraph, StateName);
|
||||
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName);
|
||||
if (!StateNode)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State '%s' not found in graph '%s'"), *StateName, *GraphName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State '%s' not found in graph '%s'"), *StateName, *GraphName));
|
||||
}
|
||||
|
||||
UEdGraph* InnerGraph = StateNode->GetBoundGraph();
|
||||
if (!InnerGraph)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("State '%s' has no bound graph"), *StateName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State '%s' has no bound graph"), *StateName));
|
||||
}
|
||||
|
||||
// Find the blend space asset
|
||||
@@ -1381,7 +1327,7 @@ void FBlueprintMCPServer::HandleSetStateBlendSpace(const FJsonObject* Json, FJso
|
||||
|
||||
if (!BlendSpaceAsset)
|
||||
{
|
||||
return MakeErrorJson(Result, FString::Printf(TEXT("Blend Space '%s' not found"), *BlendSpaceName));
|
||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Blend Space '%s' not found"), *BlendSpaceName));
|
||||
}
|
||||
|
||||
// Find existing BlendSpacePlayer or create one
|
||||
@@ -1529,7 +1475,7 @@ void FBlueprintMCPServer::HandleSetStateBlendSpace(const FJsonObject* Json, FJso
|
||||
|
||||
// Compile and save
|
||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||
bool bSaved = SaveBlueprintPackage(AnimBP);
|
||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||
|
||||
Result->SetBoolField(TEXT("success"), true);
|
||||
Result->SetStringField(TEXT("stateName"), StateName);
|
||||
|
||||
Reference in New Issue
Block a user