More MCP refactors
This commit is contained in:
@@ -243,6 +243,179 @@ UBlueprint* UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(const FString& NameOr
|
|||||||
return LoadBlueprintOrLevelBlueprint(*Asset, Error);
|
return LoadBlueprintOrLevelBlueprint(*Asset, Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// MCPAssetsBase
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
MCPAssetsBase::MCPAssetsBase(UClass* InTargetClass)
|
||||||
|
: TargetClass(InTargetClass)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPAssetsBase& MCPAssetsBase::Exact(const FString& InName)
|
||||||
|
{
|
||||||
|
MatchName = InName;
|
||||||
|
bExactMatch = true;
|
||||||
|
bPatternHasSlash = MatchName.Contains(TEXT("/"));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPAssetsBase& MCPAssetsBase::Substring(const FString& InFilter)
|
||||||
|
{
|
||||||
|
MatchName = InFilter;
|
||||||
|
bExactMatch = false;
|
||||||
|
bPatternHasSlash = MatchName.Contains(TEXT("/"));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPAssetsBase& MCPAssetsBase::NoDerived()
|
||||||
|
{
|
||||||
|
bNoDerived = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPAssetsBase& MCPAssetsBase::AllContent()
|
||||||
|
{
|
||||||
|
bAllContent = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCPAssetsBase& MCPAssetsBase::Errors(MCPErrorCallback InCB)
|
||||||
|
{
|
||||||
|
ErrorCB = InCB;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MCPAssetsBase::Info()
|
||||||
|
{
|
||||||
|
// In theory, there's no reason a person couldn't load/info
|
||||||
|
// more than once, to obtain updates. Might as well allow it.
|
||||||
|
AssetResults.Empty();
|
||||||
|
UObjectResults.Empty();
|
||||||
|
|
||||||
|
// Query the asset registry
|
||||||
|
IAssetRegistry& AR = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get();
|
||||||
|
while (AR.IsLoadingAssets()) FPlatformProcess::Sleep(0.1f);
|
||||||
|
|
||||||
|
FARFilter Filter;
|
||||||
|
TArray<FAssetData> Candidates;
|
||||||
|
ConfigureFilterClassPaths(Filter);
|
||||||
|
AR.GetAssets(Filter, Candidates);
|
||||||
|
for (const FAssetData &Data : Candidates)
|
||||||
|
{
|
||||||
|
if (AssetMatches(Data)) AssetResults.Add(Data);
|
||||||
|
if (bErrorIfAny && (AssetResults.Num() > 0))
|
||||||
|
{
|
||||||
|
SetError(FString::Printf(TEXT("%s '%s' already exists."), *TargetClass->GetName(), *AssetResults[0].PackageName.ToString()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bErrorIfTwo && (AssetResults.Num() > 1))
|
||||||
|
{
|
||||||
|
SetError(FString::Printf(
|
||||||
|
TEXT("Ambiguous %s name '%s' — matches '%s' and '%s'. Use the full package path to disambiguate."),
|
||||||
|
*TargetClass->GetName(), *MatchName, *AssetResults[0].PackageName.ToString(), *AssetResults[1].PackageName.ToString()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (AssetResults.Num() >= MaxResults) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check error conditions on the result count
|
||||||
|
if (bErrorIfNone && AssetResults.IsEmpty())
|
||||||
|
{
|
||||||
|
SetError(FString::Printf(TEXT("%s '%s' not found."), *TargetClass->GetName(), *MatchName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCPAssetsBase::Load()
|
||||||
|
{
|
||||||
|
if (!Info()) return false;
|
||||||
|
|
||||||
|
TArray<FAssetData> AssetsToLoad;
|
||||||
|
Swap(AssetsToLoad, AssetResults);
|
||||||
|
for (const FAssetData &Asset : AssetsToLoad)
|
||||||
|
{
|
||||||
|
UObject *Obj = TryLoadAsset(Asset);
|
||||||
|
if (Obj != nullptr)
|
||||||
|
{
|
||||||
|
AssetResults.Add(Asset);
|
||||||
|
UObjectResults.Add(Obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bErrorIfNone && AssetResults.IsEmpty())
|
||||||
|
{
|
||||||
|
SetError(FString::Printf(TEXT("%s '%s' exists but cannot be loaded."), *TargetClass->GetName(),
|
||||||
|
*AssetsToLoad[0].PackageName.ToString()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCPAssetsBase::ConfigureFilterClassPaths(FARFilter &Filter)
|
||||||
|
{
|
||||||
|
if (Classes.IsEmpty())
|
||||||
|
{
|
||||||
|
Filter.ClassPaths.Add(TargetClass->GetClassPathName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (UClass* C : Classes) Filter.ClassPaths.Add(C->GetClassPathName());
|
||||||
|
}
|
||||||
|
Filter.bRecursiveClasses = !bNoDerived;
|
||||||
|
if (!bAllContent)
|
||||||
|
{
|
||||||
|
Filter.PackagePaths.Add(FName(TEXT("/Game")));
|
||||||
|
Filter.bRecursivePaths = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MCPAssetsBase::AssetMatches(const FAssetData &Asset)
|
||||||
|
{
|
||||||
|
if (bExactMatch)
|
||||||
|
{
|
||||||
|
FString Name = bPatternHasSlash ? Asset.PackageName.ToString() : Asset.AssetName.ToString();
|
||||||
|
return Name.Equals(MatchName, ESearchCase::IgnoreCase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Asset.AssetName.ToString().Contains(MatchName, ESearchCase::IgnoreCase) ||
|
||||||
|
Asset.PackageName.ToString().Contains(MatchName, ESearchCase::IgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UObject *MCPAssetsBase::TryLoadAsset(const FAssetData &Asset)
|
||||||
|
{
|
||||||
|
UObject* Obj = Asset.GetAsset();
|
||||||
|
if (Obj == nullptr) return nullptr;
|
||||||
|
if (Obj->IsA(TargetClass)) return Obj;
|
||||||
|
|
||||||
|
if (TargetClass->IsChildOf(UBlueprint::StaticClass()) &&
|
||||||
|
ULevelScriptBlueprint::StaticClass()->IsChildOf(TargetClass))
|
||||||
|
{
|
||||||
|
UWorld* World = Cast<UWorld>(Obj);
|
||||||
|
if (World && World->PersistentLevel)
|
||||||
|
{
|
||||||
|
ULevelScriptBlueprint* LevelBP = World->PersistentLevel->GetLevelScriptBlueprint(true);
|
||||||
|
if (LevelBP) return LevelBP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCPAssetsBase::SetError(const FString &Msg)
|
||||||
|
{
|
||||||
|
AssetResults.Empty();
|
||||||
|
UObjectResults.Empty();
|
||||||
|
ErrorCB.SetError(Msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Load helpers
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
UAnimationStateMachineGraph* UMCPAssetFinder::LoadAnimStateMachineGraph(
|
UAnimationStateMachineGraph* UMCPAssetFinder::LoadAnimStateMachineGraph(
|
||||||
const FString& BlueprintName, const FString& GraphName, MCPErrorCallback Error)
|
const FString& BlueprintName, const FString& GraphName, MCPErrorCallback Error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -59,16 +59,13 @@ public:
|
|||||||
|
|
||||||
// Check if asset already exists
|
// Check if asset already exists
|
||||||
FString FullAssetPath = PackagePath / Name;
|
FString FullAssetPath = PackagePath / Name;
|
||||||
if (UMCPAssetFinder::FindAsset(UBlueprint::StaticClass(), Name))
|
MCPAssets<UBlueprint> ExistCheck;
|
||||||
{
|
if (!ExistCheck.Exact(Name).Errors(Result).EAny().Info()) return;
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
|
||||||
TEXT("Blueprint '%s' already exists. Use a different name or delete the existing asset first."),
|
|
||||||
*Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve skeleton
|
// Resolve skeleton
|
||||||
USkeleton* SkeletonObj = UMCPAssetFinder::LoadAsset<USkeleton>(Skeleton, Result);
|
MCPAssets<USkeleton> SkeletonAssets;
|
||||||
if (!SkeletonObj) return;
|
if (!SkeletonAssets.Exact(Skeleton).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
USkeleton* SkeletonObj = SkeletonAssets.Object();
|
||||||
|
|
||||||
// Resolve parent class (default: UAnimInstance)
|
// Resolve parent class (default: UAnimInstance)
|
||||||
UClass* ParentClassObj = UAnimInstance::StaticClass();
|
UClass* ParentClassObj = UAnimInstance::StaticClass();
|
||||||
@@ -136,13 +133,9 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created AnimBlueprint '%s' with %d graphs (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created AnimBlueprint '%s' with %d graphs (saved: %s)"),
|
||||||
*Name, GraphNames.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
*Name, GraphNames.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprintName"), Name);
|
|
||||||
Result->SetStringField(TEXT("packagePath"), PackagePath);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
||||||
Result->SetStringField(TEXT("targetSkeleton"), SkeletonObj->GetName());
|
Result->SetStringField(TEXT("targetSkeleton"), SkeletonObj->GetName());
|
||||||
Result->SetStringField(TEXT("parentClass"), ParentClassObj->GetName());
|
Result->SetStringField(TEXT("parentClass"), ParentClassObj->GetName());
|
||||||
Result->SetBoolField(TEXT("isAnimBlueprint"), true);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
||||||
}
|
}
|
||||||
@@ -173,8 +166,9 @@ public:
|
|||||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||||
}
|
}
|
||||||
|
|
||||||
UAnimBlueprint* AnimBP = UMCPAssetFinder::LoadAsset<UAnimBlueprint>(Blueprint, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!AnimBP) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
// Walk all anim nodes to collect slot names
|
// Walk all anim nodes to collect slot names
|
||||||
TSet<FString> SlotNames;
|
TSet<FString> SlotNames;
|
||||||
@@ -208,8 +202,6 @@ public:
|
|||||||
SlotsArr.Add(MakeShared<FJsonValueString>(Slot));
|
SlotsArr.Add(MakeShared<FJsonValueString>(Slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetArrayField(TEXT("slots"), SlotsArr);
|
Result->SetArrayField(TEXT("slots"), SlotsArr);
|
||||||
Result->SetNumberField(TEXT("count"), SlotsArr.Num());
|
Result->SetNumberField(TEXT("count"), SlotsArr.Num());
|
||||||
}
|
}
|
||||||
@@ -240,8 +232,9 @@ public:
|
|||||||
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
return MCPUtils::MakeErrorJson(Result, TEXT("Missing required field: blueprint"));
|
||||||
}
|
}
|
||||||
|
|
||||||
UAnimBlueprint* AnimBP = UMCPAssetFinder::LoadAsset<UAnimBlueprint>(Blueprint, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!AnimBP) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
// Walk all anim nodes to collect sync group names
|
// Walk all anim nodes to collect sync group names
|
||||||
TSet<FString> SyncGroupNames;
|
TSet<FString> SyncGroupNames;
|
||||||
@@ -275,8 +268,6 @@ public:
|
|||||||
GroupsArr.Add(MakeShared<FJsonValueString>(Group));
|
GroupsArr.Add(MakeShared<FJsonValueString>(Group));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetArrayField(TEXT("syncGroups"), GroupsArr);
|
Result->SetArrayField(TEXT("syncGroups"), GroupsArr);
|
||||||
Result->SetNumberField(TEXT("count"), GroupsArr.Num());
|
Result->SetNumberField(TEXT("count"), GroupsArr.Num());
|
||||||
}
|
}
|
||||||
@@ -321,16 +312,13 @@ public:
|
|||||||
|
|
||||||
// Check if asset already exists
|
// Check if asset already exists
|
||||||
FString FullAssetPath = PackagePath / Name;
|
FString FullAssetPath = PackagePath / Name;
|
||||||
if (UMCPAssetFinder::FindAsset(UBlendSpace::StaticClass(), Name))
|
MCPAssets<UBlendSpace> ExistCheck;
|
||||||
{
|
if (!ExistCheck.Exact(Name).Errors(Result).EAny().Info()) return;
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
|
||||||
TEXT("Blend Space '%s' already exists. Use a different name or delete the existing asset first."),
|
|
||||||
*Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve skeleton
|
// Resolve skeleton
|
||||||
USkeleton* SkeletonObj = UMCPAssetFinder::LoadAsset<USkeleton>(Skeleton, Result);
|
MCPAssets<USkeleton> SkeletonAssets;
|
||||||
if (!SkeletonObj) return;
|
if (!SkeletonAssets.Exact(Skeleton).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
USkeleton* SkeletonObj = SkeletonAssets.Object();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Blend Space '%s' in '%s' with skeleton '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Blend Space '%s' in '%s' with skeleton '%s'"),
|
||||||
*Name, *PackagePath, *SkeletonObj->GetName());
|
*Name, *PackagePath, *SkeletonObj->GetName());
|
||||||
@@ -360,7 +348,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Blend Space '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Blend Space '%s' (saved: %s)"),
|
||||||
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
||||||
Result->SetStringField(TEXT("skeleton"), SkeletonObj->GetName());
|
Result->SetStringField(TEXT("skeleton"), SkeletonObj->GetName());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -415,8 +402,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the blend space
|
// Load the blend space
|
||||||
UBlendSpace* BS = UMCPAssetFinder::LoadAsset<UBlendSpace>(BlendSpace, Result);
|
MCPAssets<UBlendSpace> Assets;
|
||||||
if (!BS) return;
|
if (!Assets.Exact(BlendSpace).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UBlendSpace* BS = Assets.Object();
|
||||||
|
|
||||||
// Set axis parameters
|
// Set axis parameters
|
||||||
BS->PreEditChange(nullptr);
|
BS->PreEditChange(nullptr);
|
||||||
@@ -458,11 +446,9 @@ public:
|
|||||||
UAnimSequence* AnimSeq = nullptr;
|
UAnimSequence* AnimSeq = nullptr;
|
||||||
if (!AnimAssetName.IsEmpty())
|
if (!AnimAssetName.IsEmpty())
|
||||||
{
|
{
|
||||||
FAssetData* FoundAnimAsset = UMCPAssetFinder::FindAsset(UAnimSequence::StaticClass(), AnimAssetName);
|
MCPAssets<UAnimSequence> AnimAssets;
|
||||||
if (FoundAnimAsset)
|
if (AnimAssets.Exact(AnimAssetName).Load())
|
||||||
{
|
AnimSeq = AnimAssets.Object();
|
||||||
AnimSeq = Cast<UAnimSequence>(FoundAnimAsset->GetAsset());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FVector SampleValue(X, Y, 0.0f);
|
FVector SampleValue(X, Y, 0.0f);
|
||||||
@@ -487,7 +473,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set %d samples on Blend Space '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set %d samples on Blend Space '%s' (saved: %s)"),
|
||||||
SamplesSet, *BS->GetName(), bSaved ? TEXT("true") : TEXT("false"));
|
SamplesSet, *BS->GetName(), bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blendSpace"), BS->GetPathName());
|
Result->SetStringField(TEXT("blendSpace"), BS->GetPathName());
|
||||||
Result->SetNumberField(TEXT("samplesSet"), SamplesSet);
|
Result->SetNumberField(TEXT("samplesSet"), SamplesSet);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
|
|||||||
@@ -152,10 +152,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), bDeleted);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
||||||
Result->SetStringField(TEXT("filename"), PackageFilename);
|
Result->SetStringField(TEXT("filename"), PackageFilename);
|
||||||
Result->SetBoolField(TEXT("forced"), Force);
|
|
||||||
if (!bDeleted)
|
if (!bDeleted)
|
||||||
{
|
{
|
||||||
MCPUtils::MakeErrorJson(Result, TEXT("Failed to delete file from disk"));
|
MCPUtils::MakeErrorJson(Result, TEXT("Failed to delete file from disk"));
|
||||||
@@ -201,17 +198,9 @@ public:
|
|||||||
TArray<FAssetRenameData> RenameData;
|
TArray<FAssetRenameData> RenameData;
|
||||||
|
|
||||||
// We need to load the asset to get the object
|
// We need to load the asset to get the object
|
||||||
FAssetData* FoundAsset = UMCPAssetFinder::FindAnyAsset(AssetPath);
|
MCPAssets<UObject> Assets;
|
||||||
if (!FoundAsset)
|
if (!Assets.Exact(AssetPath).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
{
|
UObject* AssetObj = Assets.Object();
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Asset '%s' not found. Checked Blueprints, Materials, Material Instances, and Material Functions."), *AssetPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
UObject* AssetObj = FoundAsset->GetAsset();
|
|
||||||
if (!AssetObj)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Failed to load asset '%s'"), *AssetPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse new path into package path and asset name
|
// Parse new path into package path and asset name
|
||||||
FString NewPackagePath, NewAssetName;
|
FString NewPackagePath, NewAssetName;
|
||||||
@@ -244,9 +233,6 @@ public:
|
|||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Rename %s"), bSuccess ? TEXT("succeeded") : TEXT("failed"));
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Rename %s"), bSuccess ? TEXT("succeeded") : TEXT("failed"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), bSuccess);
|
|
||||||
Result->SetStringField(TEXT("oldPath"), AssetPath);
|
|
||||||
Result->SetStringField(TEXT("newPath"), NewPath);
|
|
||||||
Result->SetStringField(TEXT("newPackagePath"), NewPackagePath);
|
Result->SetStringField(TEXT("newPackagePath"), NewPackagePath);
|
||||||
Result->SetStringField(TEXT("newAssetName"), NewAssetName);
|
Result->SetStringField(TEXT("newAssetName"), NewAssetName);
|
||||||
if (!bSuccess)
|
if (!bSuccess)
|
||||||
|
|||||||
@@ -33,12 +33,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
|
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
|
||||||
if (!SCS)
|
if (!SCS)
|
||||||
@@ -101,7 +98,6 @@ public:
|
|||||||
ComponentsArr.Add(MakeShared<FJsonValueObject>(CompObj));
|
ComponentsArr.Add(MakeShared<FJsonValueObject>(CompObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("count"), ComponentsArr.Num());
|
Result->SetNumberField(TEXT("count"), ComponentsArr.Num());
|
||||||
Result->SetArrayField(TEXT("components"), ComponentsArr);
|
Result->SetArrayField(TEXT("components"), ComponentsArr);
|
||||||
}
|
}
|
||||||
@@ -137,12 +133,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
|
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
|
||||||
if (!SCS)
|
if (!SCS)
|
||||||
@@ -265,8 +258,6 @@ public:
|
|||||||
ParentSCSNode ? *ParentComponent : TEXT("(root)"),
|
ParentSCSNode ? *ParentComponent : TEXT("(root)"),
|
||||||
bSaved ? TEXT("true") : TEXT("false"));
|
bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("component"), NewNode->GetVariableName().ToString());
|
Result->SetStringField(TEXT("component"), NewNode->GetVariableName().ToString());
|
||||||
Result->SetStringField(TEXT("componentClass"), ComponentClassObj->GetName());
|
Result->SetStringField(TEXT("componentClass"), ComponentClassObj->GetName());
|
||||||
if (ParentSCSNode)
|
if (ParentSCSNode)
|
||||||
@@ -300,12 +291,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
|
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
|
||||||
if (!SCS)
|
if (!SCS)
|
||||||
@@ -368,9 +356,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed component '%s' from '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed component '%s' from '%s' (saved: %s)"),
|
||||||
*Component, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
*Component, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("component"), Component);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,12 +41,13 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Load both blueprints
|
// Load both blueprints
|
||||||
FString LoadErrorA, LoadErrorB;
|
MCPAssets<UBlueprint> AssetsA;
|
||||||
UBlueprint* BPA = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(BlueprintA, LoadErrorA);
|
if (!AssetsA.Exact(BlueprintA).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BPA) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("blueprintA: %s"), *LoadErrorA)); return; }
|
UBlueprint* BPA = AssetsA.Object();
|
||||||
|
|
||||||
UBlueprint* BPB = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(BlueprintB, LoadErrorB);
|
MCPAssets<UBlueprint> AssetsB;
|
||||||
if (!BPB) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("blueprintB: %s"), *LoadErrorB)); return; }
|
if (!AssetsB.Exact(BlueprintB).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UBlueprint* BPB = AssetsB.Object();
|
||||||
|
|
||||||
// Helper to gather graphs from a Blueprint
|
// Helper to gather graphs from a Blueprint
|
||||||
auto GatherGraphs = [this](UBlueprint* BP) -> TArray<UEdGraph*>
|
auto GatherGraphs = [this](UBlueprint* BP) -> TArray<UEdGraph*>
|
||||||
@@ -251,9 +252,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprintA"), BlueprintA);
|
|
||||||
Result->SetStringField(TEXT("blueprintB"), BlueprintB);
|
|
||||||
Result->SetArrayField(TEXT("graphs"), GraphDiffs);
|
Result->SetArrayField(TEXT("graphs"), GraphDiffs);
|
||||||
|
|
||||||
if (VarsOnlyInA.Num() > 0) Result->SetArrayField(TEXT("variablesOnlyInA"), VarsOnlyInA);
|
if (VarsOnlyInA.Num() > 0) Result->SetArrayField(TEXT("variablesOnlyInA"), VarsOnlyInA);
|
||||||
|
|||||||
@@ -43,12 +43,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
UEdGraph* Graph = nullptr;
|
UEdGraph* Graph = nullptr;
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node, &Graph);
|
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node, &Graph);
|
||||||
@@ -78,9 +75,6 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("pinName"), Pin->PinName.ToString());
|
Result->SetStringField(TEXT("pinName"), Pin->PinName.ToString());
|
||||||
Result->SetStringField(TEXT("direction"), Pin->Direction == EGPD_Input ? TEXT("Input") : TEXT("Output"));
|
Result->SetStringField(TEXT("direction"), Pin->Direction == EGPD_Input ? TEXT("Input") : TEXT("Output"));
|
||||||
Result->SetStringField(TEXT("type"), Pin->PinType.PinCategory.ToString());
|
Result->SetStringField(TEXT("type"), Pin->PinType.PinCategory.ToString());
|
||||||
@@ -168,12 +162,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
UEdGraph* SourceGraph = nullptr;
|
UEdGraph* SourceGraph = nullptr;
|
||||||
UEdGraphNode* FoundSourceNode = MCPUtils::FindNodeByGuid(BP, SourceNode, &SourceGraph);
|
UEdGraphNode* FoundSourceNode = MCPUtils::FindNodeByGuid(BP, SourceNode, &SourceGraph);
|
||||||
@@ -209,9 +200,6 @@ public:
|
|||||||
// Check compatibility using the schema
|
// Check compatibility using the schema
|
||||||
const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
|
const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
|
|
||||||
bool bCompatible = (Response.Response != ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW);
|
bool bCompatible = (Response.Response != ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW);
|
||||||
Result->SetBoolField(TEXT("compatible"), bCompatible);
|
Result->SetBoolField(TEXT("compatible"), bCompatible);
|
||||||
|
|
||||||
@@ -371,7 +359,6 @@ public:
|
|||||||
ClassList.Add(MakeShared<FJsonValueObject>(ClassObj));
|
ClassList.Add(MakeShared<FJsonValueObject>(ClassObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetNumberField(TEXT("count"), ClassList.Num());
|
Result->SetNumberField(TEXT("count"), ClassList.Num());
|
||||||
Result->SetNumberField(TEXT("totalMatched"), TotalMatched);
|
Result->SetNumberField(TEXT("totalMatched"), TotalMatched);
|
||||||
if (TotalMatched > Limit)
|
if (TotalMatched > Limit)
|
||||||
@@ -494,7 +481,6 @@ public:
|
|||||||
FuncList.Add(MakeShared<FJsonValueObject>(FuncObj));
|
FuncList.Add(MakeShared<FJsonValueObject>(FuncObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("className"), FoundClass->GetName());
|
Result->SetStringField(TEXT("className"), FoundClass->GetName());
|
||||||
Result->SetNumberField(TEXT("count"), FuncList.Num());
|
Result->SetNumberField(TEXT("count"), FuncList.Num());
|
||||||
Result->SetArrayField(TEXT("functions"), FuncList);
|
Result->SetArrayField(TEXT("functions"), FuncList);
|
||||||
@@ -587,7 +573,6 @@ public:
|
|||||||
PropList.Add(MakeShared<FJsonValueObject>(PropObj));
|
PropList.Add(MakeShared<FJsonValueObject>(PropObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("className"), FoundClass->GetName());
|
Result->SetStringField(TEXT("className"), FoundClass->GetName());
|
||||||
Result->SetNumberField(TEXT("count"), PropList.Num());
|
Result->SetNumberField(TEXT("count"), PropList.Num());
|
||||||
Result->SetArrayField(TEXT("properties"), PropList);
|
Result->SetArrayField(TEXT("properties"), PropList);
|
||||||
@@ -604,6 +589,9 @@ class UMCPHandler_ShowCommands : public UObject, public IMCPHandler
|
|||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
UPROPERTY(meta=(Optional, Description="If true, return full details including parameter types and descriptions"))
|
||||||
|
bool Verbose = false;
|
||||||
|
|
||||||
virtual FString GetDescription() const override
|
virtual FString GetDescription() const override
|
||||||
{
|
{
|
||||||
return TEXT("List all available commands with their descriptions.");
|
return TEXT("List all available commands with their descriptions.");
|
||||||
@@ -611,7 +599,8 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
TArray<TSharedPtr<FJsonValue>> CommandsArray;
|
// Collect all handler classes sorted by tool name
|
||||||
|
TArray<TPair<FString, UClass*>> Handlers;
|
||||||
for (TObjectIterator<UClass> It; It; ++It)
|
for (TObjectIterator<UClass> It; It; ++It)
|
||||||
{
|
{
|
||||||
UClass* Class = *It;
|
UClass* Class = *It;
|
||||||
@@ -620,9 +609,41 @@ public:
|
|||||||
if (!Handler) continue;
|
if (!Handler) continue;
|
||||||
const FString& ToolName = Class->GetMetaData(TEXT("ToolName"));
|
const FString& ToolName = Class->GetMetaData(TEXT("ToolName"));
|
||||||
if (ToolName.IsEmpty()) continue;
|
if (ToolName.IsEmpty()) continue;
|
||||||
|
Handlers.Add({ToolName, Class});
|
||||||
|
}
|
||||||
|
Handlers.Sort();
|
||||||
|
|
||||||
|
if (!Verbose)
|
||||||
|
{
|
||||||
|
// Compact format: "command_name(param1,param2,?optional)"
|
||||||
|
TArray<TSharedPtr<FJsonValue>> Lines;
|
||||||
|
for (const auto& Pair : Handlers)
|
||||||
|
{
|
||||||
|
FString Line = Pair.Key + TEXT("(");
|
||||||
|
bool bFirst = true;
|
||||||
|
for (TFieldIterator<FProperty> PropIt(Pair.Value, EFieldIterationFlags::None); PropIt; ++PropIt)
|
||||||
|
{
|
||||||
|
if (!bFirst) Line += TEXT(",");
|
||||||
|
bFirst = false;
|
||||||
|
if (PropIt->HasMetaData(TEXT("Optional"))) Line += TEXT("?");
|
||||||
|
Line += MCPUtils::PropertyNameToJsonKey(PropIt->GetName());
|
||||||
|
}
|
||||||
|
Line += TEXT(")");
|
||||||
|
Lines.Add(MakeShared<FJsonValueString>(Line));
|
||||||
|
}
|
||||||
|
Result->SetNumberField(TEXT("count"), Lines.Num());
|
||||||
|
Result->SetArrayField(TEXT("commands"), Lines);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<TSharedPtr<FJsonValue>> CommandsArray;
|
||||||
|
for (const auto& Pair : Handlers)
|
||||||
|
{
|
||||||
|
UClass* Class = Pair.Value;
|
||||||
|
const IMCPHandler* Handler = Cast<IMCPHandler>(Class->GetDefaultObject());
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
||||||
Entry->SetStringField(TEXT("command"), ToolName);
|
Entry->SetStringField(TEXT("command"), Pair.Key);
|
||||||
Entry->SetStringField(TEXT("description"), Handler->GetDescription());
|
Entry->SetStringField(TEXT("description"), Handler->GetDescription());
|
||||||
|
|
||||||
// Document parameters from UPROPERTY fields
|
// Document parameters from UPROPERTY fields
|
||||||
|
|||||||
@@ -39,12 +39,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
FName DispatcherFName(*DispatcherName);
|
FName DispatcherFName(*DispatcherName);
|
||||||
|
|
||||||
@@ -155,9 +152,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added event dispatcher '%s' to '%s' with %d params (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added event dispatcher '%s' to '%s' with %d params (saved: %s)"),
|
||||||
*DispatcherName, *Blueprint, AddedParamsJson.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
*DispatcherName, *Blueprint, AddedParamsJson.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("dispatcherName"), DispatcherName);
|
|
||||||
Result->SetArrayField(TEXT("parameters"), AddedParamsJson);
|
Result->SetArrayField(TEXT("parameters"), AddedParamsJson);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
@@ -183,12 +177,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TSet<FName> DelegateNameSet;
|
TSet<FName> DelegateNameSet;
|
||||||
FBlueprintEditorUtils::GetDelegateNameList(BP, DelegateNameSet);
|
FBlueprintEditorUtils::GetDelegateNameList(BP, DelegateNameSet);
|
||||||
@@ -236,7 +227,6 @@ public:
|
|||||||
DispatchersArr.Add(MakeShared<FJsonValueObject>(DispObj));
|
DispatchersArr.Add(MakeShared<FJsonValueObject>(DispObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("count"), DispatchersArr.Num());
|
Result->SetNumberField(TEXT("count"), DispatchersArr.Num());
|
||||||
Result->SetArrayField(TEXT("dispatchers"), DispatchersArr);
|
Result->SetArrayField(TEXT("dispatchers"), DispatchersArr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,12 +38,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
FString OldParentName = BP->ParentClass ? BP->ParentClass->GetName() : TEXT("None");
|
FString OldParentName = BP->ParentClass ? BP->ParentClass->GetName() : TEXT("None");
|
||||||
|
|
||||||
@@ -64,11 +61,12 @@ public:
|
|||||||
// If not found as C++ class, try loading as a Blueprint asset
|
// If not found as C++ class, try loading as a Blueprint asset
|
||||||
if (!NewParentClassObj)
|
if (!NewParentClassObj)
|
||||||
{
|
{
|
||||||
FString ParentLoadError;
|
MCPAssets<UBlueprint> ParentAssets;
|
||||||
UBlueprint* ParentBP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(NewParentClass, ParentLoadError);
|
if (!ParentAssets.Exact(NewParentClass).AllContent().Errors(Result).ETwo().Load()) return;
|
||||||
if (ParentBP && ParentBP->GeneratedClass)
|
if (!ParentAssets.Objects().IsEmpty())
|
||||||
{
|
{
|
||||||
NewParentClassObj = ParentBP->GeneratedClass;
|
if (ParentAssets.Object()->GeneratedClass)
|
||||||
|
NewParentClassObj = ParentAssets.Object()->GeneratedClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,8 +107,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Reparent complete, save %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Reparent complete, save %s"),
|
||||||
bSaved ? TEXT("succeeded") : TEXT("failed"));
|
bSaved ? TEXT("succeeded") : TEXT("failed"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("oldParentClass"), OldParentName);
|
Result->SetStringField(TEXT("oldParentClass"), OldParentName);
|
||||||
Result->SetStringField(TEXT("newParentClass"), NewParentActualName);
|
Result->SetStringField(TEXT("newParentClass"), NewParentActualName);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -154,12 +150,8 @@ public:
|
|||||||
|
|
||||||
// Check if asset already exists
|
// Check if asset already exists
|
||||||
FString FullAssetPath = PackagePath / Blueprint;
|
FString FullAssetPath = PackagePath / Blueprint;
|
||||||
if (UMCPAssetFinder::FindAsset(UBlueprint::StaticClass(), Blueprint) || UMCPAssetFinder::FindAsset(UBlueprint::StaticClass(), FullAssetPath))
|
MCPAssets<UBlueprint> ExistCheck;
|
||||||
{
|
if (!ExistCheck.Exact(Blueprint).Errors(Result).EAny().Info()) return;
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
|
||||||
TEXT("Blueprint '%s' already exists. Use a different name or delete the existing asset first."),
|
|
||||||
*Blueprint));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve parent class — try C++ class first, then Blueprint
|
// Resolve parent class — try C++ class first, then Blueprint
|
||||||
UClass* ParentClassObj = nullptr;
|
UClass* ParentClassObj = nullptr;
|
||||||
@@ -175,11 +167,12 @@ public:
|
|||||||
|
|
||||||
if (!ParentClassObj)
|
if (!ParentClassObj)
|
||||||
{
|
{
|
||||||
FString ParentLoadError;
|
MCPAssets<UBlueprint> ParentAssets;
|
||||||
UBlueprint* ParentBP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(ParentClass, ParentLoadError);
|
if (!ParentAssets.Exact(ParentClass).AllContent().Errors(Result).ETwo().Load()) return;
|
||||||
if (ParentBP && ParentBP->GeneratedClass)
|
if (!ParentAssets.Objects().IsEmpty())
|
||||||
{
|
{
|
||||||
ParentClassObj = ParentBP->GeneratedClass;
|
if (ParentAssets.Object()->GeneratedClass)
|
||||||
|
ParentClassObj = ParentAssets.Object()->GeneratedClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,12 +265,8 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Blueprint '%s' with %d graphs (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Blueprint '%s' with %d graphs (saved: %s)"),
|
||||||
*Blueprint, GraphNames.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
*Blueprint, GraphNames.Num(), bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprintName"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("packagePath"), PackagePath);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
Result->SetStringField(TEXT("assetPath"), FullAssetPath);
|
||||||
Result->SetStringField(TEXT("parentClass"), ParentClassObj->GetName());
|
Result->SetStringField(TEXT("parentClass"), ParentClassObj->GetName());
|
||||||
Result->SetStringField(TEXT("blueprintType"), BlueprintType.IsEmpty() ? TEXT("Normal") : *BlueprintType);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
Result->SetArrayField(TEXT("graphs"), GraphNames);
|
||||||
}
|
}
|
||||||
@@ -316,12 +305,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check graph name uniqueness
|
// Check graph name uniqueness
|
||||||
TArray<UEdGraph*> AllGraphs;
|
TArray<UEdGraph*> AllGraphs;
|
||||||
@@ -410,10 +396,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created %s graph '%s' in '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created %s graph '%s' in '%s' (saved: %s)"),
|
||||||
*GraphType, *Graph, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
*GraphType, *Graph, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("graphName"), Graph);
|
|
||||||
Result->SetStringField(TEXT("graphType"), GraphType);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
if (!CreatedNodeId.IsEmpty())
|
if (!CreatedNodeId.IsEmpty())
|
||||||
{
|
{
|
||||||
@@ -445,12 +427,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the graph
|
// Find the graph
|
||||||
UEdGraph* TargetGraph = nullptr;
|
UEdGraph* TargetGraph = nullptr;
|
||||||
@@ -508,9 +487,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Deleted graph '%s' (%d nodes), save %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Deleted graph '%s' (%d nodes), save %s"),
|
||||||
*Graph, NodeCount, bSaved ? TEXT("true") : TEXT("false"));
|
*Graph, NodeCount, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("graphName"), Graph);
|
|
||||||
Result->SetStringField(TEXT("graphType"), GraphType);
|
Result->SetStringField(TEXT("graphType"), GraphType);
|
||||||
Result->SetNumberField(TEXT("nodeCount"), NodeCount);
|
Result->SetNumberField(TEXT("nodeCount"), NodeCount);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -543,12 +519,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if it's an UbergraphPage — disallow rename
|
// Check if it's an UbergraphPage — disallow rename
|
||||||
for (UEdGraph* CandidateGraph : BP->UbergraphPages)
|
for (UEdGraph* CandidateGraph : BP->UbergraphPages)
|
||||||
@@ -615,9 +588,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Renamed graph '%s' to '%s', save %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Renamed graph '%s' to '%s', save %s"),
|
||||||
*Graph, *NewName, bSaved ? TEXT("true") : TEXT("false"));
|
*Graph, *NewName, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("oldName"), Graph);
|
|
||||||
Result->SetStringField(TEXT("newName"), TargetGraph->GetName());
|
Result->SetStringField(TEXT("newName"), TargetGraph->GetName());
|
||||||
Result->SetStringField(TEXT("graphType"), GraphType);
|
Result->SetStringField(TEXT("graphType"), GraphType);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
|
|||||||
@@ -33,12 +33,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> InterfacesArr;
|
TArray<TSharedPtr<FJsonValue>> InterfacesArr;
|
||||||
for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
|
for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
|
||||||
@@ -65,7 +62,6 @@ public:
|
|||||||
InterfacesArr.Add(MakeShared<FJsonValueObject>(IfaceObj));
|
InterfacesArr.Add(MakeShared<FJsonValueObject>(IfaceObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("count"), InterfacesArr.Num());
|
Result->SetNumberField(TEXT("count"), InterfacesArr.Num());
|
||||||
Result->SetArrayField(TEXT("interfaces"), InterfacesArr);
|
Result->SetArrayField(TEXT("interfaces"), InterfacesArr);
|
||||||
}
|
}
|
||||||
@@ -96,12 +92,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve the interface class
|
// Resolve the interface class
|
||||||
UClass* InterfaceClass = nullptr;
|
UClass* InterfaceClass = nullptr;
|
||||||
@@ -137,11 +130,13 @@ public:
|
|||||||
// Strategy 2: Try loading as a Blueprint Interface asset
|
// Strategy 2: Try loading as a Blueprint Interface asset
|
||||||
if (!InterfaceClass)
|
if (!InterfaceClass)
|
||||||
{
|
{
|
||||||
FString IfaceLoadError;
|
MCPAssets<UBlueprint> IfaceAssets;
|
||||||
UBlueprint* IfaceBP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(InterfaceName, IfaceLoadError);
|
if (!IfaceAssets.Exact(InterfaceName).AllContent().Errors(Result).ETwo().Load()) return;
|
||||||
if (IfaceBP && IfaceBP->GeneratedClass && IfaceBP->GeneratedClass->IsChildOf(UInterface::StaticClass()))
|
if (!IfaceAssets.Objects().IsEmpty())
|
||||||
{
|
{
|
||||||
InterfaceClass = IfaceBP->GeneratedClass;
|
UClass* GenClass = IfaceAssets.Object()->GeneratedClass;
|
||||||
|
if (GenClass && GenClass->IsChildOf(UInterface::StaticClass()))
|
||||||
|
InterfaceClass = GenClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +194,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added interface '%s' to '%s' (%d function stubs)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added interface '%s' to '%s' (%d function stubs)"),
|
||||||
*InterfaceClass->GetName(), *Blueprint, AddedFunctions.Num());
|
*InterfaceClass->GetName(), *Blueprint, AddedFunctions.Num());
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("interfaceName"), InterfaceClass->GetName());
|
Result->SetStringField(TEXT("interfaceName"), InterfaceClass->GetName());
|
||||||
Result->SetStringField(TEXT("interfacePath"), InterfaceClass->GetPathName());
|
Result->SetStringField(TEXT("interfacePath"), InterfaceClass->GetPathName());
|
||||||
|
|
||||||
@@ -241,12 +234,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the interface in ImplementedInterfaces by name (case-insensitive)
|
// Find the interface in ImplementedInterfaces by name (case-insensitive)
|
||||||
UClass* FoundInterface = nullptr;
|
UClass* FoundInterface = nullptr;
|
||||||
@@ -308,9 +298,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed interface '%s' from '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed interface '%s' from '%s'"),
|
||||||
*FoundInterface->GetName(), *Blueprint);
|
*FoundInterface->GetName(), *Blueprint);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("interfaceName"), FoundInterface->GetName());
|
Result->SetStringField(TEXT("interfaceName"), FoundInterface->GetName());
|
||||||
Result->SetBoolField(TEXT("preservedFunctions"), PreserveFunctions);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -50,30 +50,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if asset already exists
|
// Check if asset already exists
|
||||||
FString FullAssetPath = PackagePath / Name;
|
|
||||||
if (UMCPAssetFinder::FindAsset(UMaterialInstanceConstant::StaticClass(), Name) || UMCPAssetFinder::FindAsset(UMaterialInstanceConstant::StaticClass(), FullAssetPath))
|
|
||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
MCPAssets<UMaterialInstanceConstant> ExistCheck;
|
||||||
TEXT("Material Instance '%s' already exists. Use a different name or delete the existing asset first."),
|
if (!ExistCheck.Exact(Name).Errors(Result).EAny().Info()) return;
|
||||||
*Name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load parent material — try as Material first, then as Material Instance
|
// Load parent material — try as Material first, then as Material Instance
|
||||||
UMaterialInterface* ParentMaterialObj = nullptr;
|
UMaterialInterface* ParentMaterialObj = nullptr;
|
||||||
{
|
{
|
||||||
FString LoadError;
|
MCPAssets<UMaterial> MatAssets;
|
||||||
UMaterial* ParentMat = UMCPAssetFinder::LoadAsset<UMaterial>(ParentMaterial, LoadError);
|
if (MatAssets.Exact(ParentMaterial).ETwo().Load() && !MatAssets.Objects().IsEmpty())
|
||||||
if (ParentMat)
|
|
||||||
{
|
{
|
||||||
ParentMaterialObj = ParentMat;
|
ParentMaterialObj = MatAssets.Object();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FString MILoadError;
|
MCPAssets<UMaterialInstanceConstant> MIAssets;
|
||||||
UMaterialInstanceConstant* ParentMI = UMCPAssetFinder::LoadAsset<UMaterialInstanceConstant>(ParentMaterial, MILoadError);
|
if (MIAssets.Exact(ParentMaterial).ETwo().Load() && !MIAssets.Objects().IsEmpty())
|
||||||
if (ParentMI)
|
|
||||||
{
|
{
|
||||||
ParentMaterialObj = ParentMI;
|
ParentMaterialObj = MIAssets.Object();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,8 +117,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Material Instance '%s' with parent '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Material Instance '%s' with parent '%s' (saved: %s)"),
|
||||||
*Name, *ParentMaterialObj->GetName(), bSaved ? TEXT("true") : TEXT("false"));
|
*Name, *ParentMaterialObj->GetName(), bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("name"), Name);
|
|
||||||
Result->SetStringField(TEXT("path"), MI->GetPathName());
|
Result->SetStringField(TEXT("path"), MI->GetPathName());
|
||||||
Result->SetStringField(TEXT("parent"), ParentMaterialObj->GetPathName());
|
Result->SetStringField(TEXT("parent"), ParentMaterialObj->GetPathName());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -169,8 +162,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the Material Instance
|
// Load the Material Instance
|
||||||
UMaterialInstanceConstant* MI = UMCPAssetFinder::LoadAsset<UMaterialInstanceConstant>(MaterialInstance, Result);
|
MCPAssets<UMaterialInstanceConstant> Assets;
|
||||||
if (!MI) return;
|
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterialInstanceConstant* MI = Assets.Object();
|
||||||
|
|
||||||
// Determine the parameter type — explicit or auto-detect from parent
|
// Determine the parameter type — explicit or auto-detect from parent
|
||||||
FString TypeStr = Type;
|
FString TypeStr = Type;
|
||||||
@@ -359,9 +353,6 @@ public:
|
|||||||
DryRun ? TEXT("[DRY RUN] Would set") : TEXT("Set"),
|
DryRun ? TEXT("[DRY RUN] Would set") : TEXT("Set"),
|
||||||
*ParameterName, *NewValueDescription, *MaterialInstance);
|
*ParameterName, *NewValueDescription, *MaterialInstance);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("materialInstance"), MaterialInstance);
|
|
||||||
Result->SetStringField(TEXT("parameterName"), ParameterName);
|
|
||||||
Result->SetStringField(TEXT("type"), TypeStr);
|
Result->SetStringField(TEXT("type"), TypeStr);
|
||||||
Result->SetStringField(TEXT("newValue"), NewValueDescription);
|
Result->SetStringField(TEXT("newValue"), NewValueDescription);
|
||||||
if (DryRun)
|
if (DryRun)
|
||||||
@@ -391,8 +382,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UMaterialInstanceConstant* MI = UMCPAssetFinder::LoadAsset<UMaterialInstanceConstant>(MaterialInstance, Result);
|
MCPAssets<UMaterialInstanceConstant> Assets;
|
||||||
if (!MI) return;
|
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterialInstanceConstant* MI = Assets.Object();
|
||||||
|
|
||||||
Result->SetStringField(TEXT("name"), MI->GetName());
|
Result->SetStringField(TEXT("name"), MI->GetName());
|
||||||
Result->SetStringField(TEXT("path"), MI->GetPathName());
|
Result->SetStringField(TEXT("path"), MI->GetPathName());
|
||||||
@@ -643,8 +635,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load the Material Instance
|
// Load the Material Instance
|
||||||
UMaterialInstanceConstant* MI = UMCPAssetFinder::LoadAsset<UMaterialInstanceConstant>(MaterialInstance, Result);
|
MCPAssets<UMaterialInstanceConstant> Assets;
|
||||||
if (!MI) return;
|
if (!Assets.Exact(MaterialInstance).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterialInstanceConstant* MI = Assets.Object();
|
||||||
|
|
||||||
// Capture old parent
|
// Capture old parent
|
||||||
FString OldParentPath = MI->Parent ? MI->Parent->GetPathName() : TEXT("None");
|
FString OldParentPath = MI->Parent ? MI->Parent->GetPathName() : TEXT("None");
|
||||||
@@ -652,19 +645,17 @@ public:
|
|||||||
// Load new parent — try as Material first, then as Material Instance
|
// Load new parent — try as Material first, then as Material Instance
|
||||||
UMaterialInterface* NewParentObj = nullptr;
|
UMaterialInterface* NewParentObj = nullptr;
|
||||||
{
|
{
|
||||||
FString MatLoadError;
|
MCPAssets<UMaterial> MatAssets;
|
||||||
UMaterial* NewParentMat = UMCPAssetFinder::LoadAsset<UMaterial>(NewParent, MatLoadError);
|
if (MatAssets.Exact(NewParent).ETwo().Load() && !MatAssets.Objects().IsEmpty())
|
||||||
if (NewParentMat)
|
|
||||||
{
|
{
|
||||||
NewParentObj = NewParentMat;
|
NewParentObj = MatAssets.Object();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FString MILoadError;
|
MCPAssets<UMaterialInstanceConstant> MIAssets;
|
||||||
UMaterialInstanceConstant* NewParentMI = UMCPAssetFinder::LoadAsset<UMaterialInstanceConstant>(NewParent, MILoadError);
|
if (MIAssets.Exact(NewParent).ETwo().Load() && !MIAssets.Objects().IsEmpty())
|
||||||
if (NewParentMI)
|
|
||||||
{
|
{
|
||||||
NewParentObj = NewParentMI;
|
NewParentObj = MIAssets.Object();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -721,8 +712,6 @@ public:
|
|||||||
*MaterialInstance, bSaved ? TEXT("true") : TEXT("false"));
|
*MaterialInstance, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("materialInstance"), MaterialInstance);
|
|
||||||
Result->SetStringField(TEXT("oldParent"), OldParentPath);
|
Result->SetStringField(TEXT("oldParent"), OldParentPath);
|
||||||
Result->SetStringField(TEXT("newParent"), NewParentObj->GetPathName());
|
Result->SetStringField(TEXT("newParent"), NewParentObj->GetPathName());
|
||||||
if (DryRun)
|
if (DryRun)
|
||||||
|
|||||||
@@ -92,13 +92,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if asset already exists
|
// Check if asset already exists
|
||||||
FString FullAssetPath = PackagePath / Name;
|
MCPAssets<UMaterial> ExistCheck;
|
||||||
if (UMCPAssetFinder::FindAsset(UMaterial::StaticClass(), Name) || UMCPAssetFinder::FindAsset(UMaterial::StaticClass(), FullAssetPath))
|
if (!ExistCheck.Exact(Name).Errors(Result).EAny().Info()) return;
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
|
||||||
TEXT("Material '%s' already exists. Use a different name or delete the existing asset first."),
|
|
||||||
*Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Material '%s' in '%s'"), *Name, *PackagePath);
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Material '%s' in '%s'"), *Name, *PackagePath);
|
||||||
|
|
||||||
@@ -197,8 +192,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Material '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Material '%s' (saved: %s)"),
|
||||||
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("name"), Name);
|
|
||||||
Result->SetStringField(TEXT("path"), MaterialObj->GetPathName());
|
Result->SetStringField(TEXT("path"), MaterialObj->GetPathName());
|
||||||
Result->SetStringField(TEXT("domain"), DomainToString(MaterialObj->MaterialDomain));
|
Result->SetStringField(TEXT("domain"), DomainToString(MaterialObj->MaterialDomain));
|
||||||
Result->SetStringField(TEXT("blendMode"), BlendModeToString(MaterialObj->BlendMode));
|
Result->SetStringField(TEXT("blendMode"), BlendModeToString(MaterialObj->BlendMode));
|
||||||
@@ -240,8 +233,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load material
|
// Load material
|
||||||
UMaterial* MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> Assets;
|
||||||
if (!MaterialObj) return;
|
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterial* MaterialObj = Assets.Object();
|
||||||
|
|
||||||
FString OldValue;
|
FString OldValue;
|
||||||
FString NewValue;
|
FString NewValue;
|
||||||
@@ -490,9 +484,7 @@ public:
|
|||||||
DryRun ? TEXT("[DRY RUN] ") : TEXT(""),
|
DryRun ? TEXT("[DRY RUN] ") : TEXT(""),
|
||||||
*Property, *Material, *OldValue, *NewValue);
|
*Property, *Material, *OldValue, *NewValue);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), MaterialObj->GetName());
|
Result->SetStringField(TEXT("material"), MaterialObj->GetName());
|
||||||
Result->SetStringField(TEXT("property"), Property);
|
|
||||||
Result->SetStringField(TEXT("oldValue"), OldValue);
|
Result->SetStringField(TEXT("oldValue"), OldValue);
|
||||||
Result->SetStringField(TEXT("newValue"), NewValue);
|
Result->SetStringField(TEXT("newValue"), NewValue);
|
||||||
Result->SetBoolField(TEXT("dryRun"), DryRun);
|
Result->SetBoolField(TEXT("dryRun"), DryRun);
|
||||||
@@ -593,15 +585,17 @@ public:
|
|||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, TEXT("Specify either 'material' or 'materialFunction', not both"));
|
return MCPUtils::MakeErrorJson(Result, TEXT("Specify either 'material' or 'materialFunction', not both"));
|
||||||
}
|
}
|
||||||
MatFunc = UMCPAssetFinder::LoadAsset<UMaterialFunction>(MaterialFunction, Result);
|
MCPAssets<UMaterialFunction> MFAssets;
|
||||||
if (!MatFunc) return;
|
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MatFunc = MFAssets.Object();
|
||||||
Owner = MatFunc;
|
Owner = MatFunc;
|
||||||
AssetDisplayName = MatFunc->GetName();
|
AssetDisplayName = MatFunc->GetName();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> MatAssets;
|
||||||
if (!MaterialObj) return;
|
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MaterialObj = MatAssets.Object();
|
||||||
Owner = MaterialObj;
|
Owner = MaterialObj;
|
||||||
AssetDisplayName = MaterialObj->GetName();
|
AssetDisplayName = MaterialObj->GetName();
|
||||||
}
|
}
|
||||||
@@ -611,12 +605,8 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would add expression '%s' to '%s' at (%d, %d)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would add expression '%s' to '%s' at (%d, %d)"),
|
||||||
*ExpressionClass, *AssetDisplayName, PosX, PosY);
|
*ExpressionClass, *AssetDisplayName, PosX, PosY);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("expressionClass"), ExpressionClass);
|
|
||||||
Result->SetNumberField(TEXT("posX"), PosX);
|
|
||||||
Result->SetNumberField(TEXT("posY"), PosY);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -687,12 +677,8 @@ public:
|
|||||||
// Serialize the expression details
|
// Serialize the expression details
|
||||||
TSharedPtr<FJsonObject> ExprDetails = MCPUtils::SerializeMaterialExpression(NewExpr);
|
TSharedPtr<FJsonObject> ExprDetails = MCPUtils::SerializeMaterialExpression(NewExpr);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("expressionClass"), ExpressionClass);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), NodeGuid);
|
Result->SetStringField(TEXT("nodeId"), NodeGuid);
|
||||||
Result->SetNumberField(TEXT("posX"), PosX);
|
|
||||||
Result->SetNumberField(TEXT("posY"), PosY);
|
|
||||||
if (ExprDetails.IsValid())
|
if (ExprDetails.IsValid())
|
||||||
{
|
{
|
||||||
Result->SetObjectField(TEXT("expression"), ExprDetails);
|
Result->SetObjectField(TEXT("expression"), ExprDetails);
|
||||||
@@ -742,14 +728,16 @@ public:
|
|||||||
|
|
||||||
if (!MaterialFunction.IsEmpty())
|
if (!MaterialFunction.IsEmpty())
|
||||||
{
|
{
|
||||||
MatFunc = UMCPAssetFinder::LoadAsset<UMaterialFunction>(MaterialFunction, Result);
|
MCPAssets<UMaterialFunction> MFAssets;
|
||||||
if (!MatFunc) return;
|
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MatFunc = MFAssets.Object();
|
||||||
AssetDisplayName = MatFunc->GetName();
|
AssetDisplayName = MatFunc->GetName();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> MatAssets;
|
||||||
if (!MaterialObj) return;
|
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MaterialObj = MatAssets.Object();
|
||||||
AssetDisplayName = MaterialObj->GetName();
|
AssetDisplayName = MaterialObj->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,10 +780,8 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would delete expression '%s' (nodeId: %s) from '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would delete expression '%s' (nodeId: %s) from '%s'"),
|
||||||
*DeletedExprClass, *Node, *AssetDisplayName);
|
*DeletedExprClass, *Node, *AssetDisplayName);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("deletedNode"), Node);
|
|
||||||
Result->SetStringField(TEXT("deletedNodeTitle"), DeletedNodeTitle);
|
Result->SetStringField(TEXT("deletedNodeTitle"), DeletedNodeTitle);
|
||||||
Result->SetStringField(TEXT("deletedExpressionClass"), DeletedExprClass);
|
Result->SetStringField(TEXT("deletedExpressionClass"), DeletedExprClass);
|
||||||
return;
|
return;
|
||||||
@@ -827,9 +813,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Deleted expression '%s' (nodeId: %s) from '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Deleted expression '%s' (nodeId: %s) from '%s' (saved: %s)"),
|
||||||
*DeletedExprClass, *Node, *AssetDisplayName, bSaved ? TEXT("true") : TEXT("false"));
|
*DeletedExprClass, *Node, *AssetDisplayName, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("deletedNode"), Node);
|
|
||||||
Result->SetStringField(TEXT("deletedNodeTitle"), DeletedNodeTitle);
|
Result->SetStringField(TEXT("deletedNodeTitle"), DeletedNodeTitle);
|
||||||
Result->SetStringField(TEXT("deletedExpressionClass"), DeletedExprClass);
|
Result->SetStringField(TEXT("deletedExpressionClass"), DeletedExprClass);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -886,14 +870,16 @@ public:
|
|||||||
|
|
||||||
if (!MaterialFunction.IsEmpty())
|
if (!MaterialFunction.IsEmpty())
|
||||||
{
|
{
|
||||||
MatFunc = UMCPAssetFinder::LoadAsset<UMaterialFunction>(MaterialFunction, Result);
|
MCPAssets<UMaterialFunction> MFAssets;
|
||||||
if (!MatFunc) return;
|
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MatFunc = MFAssets.Object();
|
||||||
AssetDisplayName = MatFunc->GetName();
|
AssetDisplayName = MatFunc->GetName();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> MatAssets;
|
||||||
if (!MaterialObj) return;
|
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MaterialObj = MatAssets.Object();
|
||||||
AssetDisplayName = MaterialObj->GetName();
|
AssetDisplayName = MaterialObj->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -967,9 +953,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would connect %s.%s -> %s.%s in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would connect %s.%s -> %s.%s in '%s'"),
|
||||||
*SourceNode, *SourcePinName, *TargetNode, *TargetPinName, *AssetDisplayName);
|
*SourceNode, *SourcePinName, *TargetNode, *TargetPinName, *AssetDisplayName);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetBoolField(TEXT("connected"), false);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -986,8 +970,6 @@ public:
|
|||||||
|
|
||||||
bool bConnected = Schema->TryCreateConnection(SourcePin, TargetPin);
|
bool bConnected = Schema->TryCreateConnection(SourcePin, TargetPin);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), bConnected);
|
|
||||||
Result->SetBoolField(TEXT("connected"), bConnected);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
|
|
||||||
if (!bConnected)
|
if (!bConnected)
|
||||||
@@ -1050,14 +1032,16 @@ public:
|
|||||||
|
|
||||||
if (!MaterialFunction.IsEmpty())
|
if (!MaterialFunction.IsEmpty())
|
||||||
{
|
{
|
||||||
MatFunc = UMCPAssetFinder::LoadAsset<UMaterialFunction>(MaterialFunction, Result);
|
MCPAssets<UMaterialFunction> MFAssets;
|
||||||
if (!MatFunc) return;
|
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MatFunc = MFAssets.Object();
|
||||||
AssetDisplayName = MatFunc->GetName();
|
AssetDisplayName = MatFunc->GetName();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> MatAssets;
|
||||||
if (!MaterialObj) return;
|
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MaterialObj = MatAssets.Object();
|
||||||
AssetDisplayName = MaterialObj->GetName();
|
AssetDisplayName = MaterialObj->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1109,11 +1093,8 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would disconnect pin '%s' on node '%s' in '%s' (%d links)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would disconnect pin '%s' on node '%s' in '%s' (%d links)"),
|
||||||
*PinName, *Node, *AssetDisplayName, BrokenCount);
|
*PinName, *Node, *AssetDisplayName, BrokenCount);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("pinName"), PinName);
|
|
||||||
Result->SetNumberField(TEXT("brokenLinkCount"), BrokenCount);
|
Result->SetNumberField(TEXT("brokenLinkCount"), BrokenCount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1131,10 +1112,7 @@ public:
|
|||||||
// Save
|
// Save
|
||||||
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
|
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("pinName"), PinName);
|
|
||||||
Result->SetNumberField(TEXT("brokenLinkCount"), BrokenCount);
|
Result->SetNumberField(TEXT("brokenLinkCount"), BrokenCount);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
@@ -1184,14 +1162,16 @@ public:
|
|||||||
|
|
||||||
if (!MaterialFunction.IsEmpty())
|
if (!MaterialFunction.IsEmpty())
|
||||||
{
|
{
|
||||||
MatFunc = UMCPAssetFinder::LoadAsset<UMaterialFunction>(MaterialFunction, Result);
|
MCPAssets<UMaterialFunction> MFAssets;
|
||||||
if (!MatFunc) return;
|
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MatFunc = MFAssets.Object();
|
||||||
AssetDisplayName = MatFunc->GetName();
|
AssetDisplayName = MatFunc->GetName();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> MatAssets;
|
||||||
if (!MaterialObj) return;
|
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MaterialObj = MatAssets.Object();
|
||||||
AssetDisplayName = MaterialObj->GetName();
|
AssetDisplayName = MaterialObj->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1414,9 +1394,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set expression value on node '%s' (%s) in '%s': %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set expression value on node '%s' (%s) in '%s': %s"),
|
||||||
*Node, *ExprType, *AssetDisplayName, *NewValueStr);
|
*Node, *ExprType, *AssetDisplayName, *NewValueStr);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("expressionType"), ExprType);
|
Result->SetStringField(TEXT("expressionType"), ExprType);
|
||||||
Result->SetStringField(TEXT("newValue"), NewValueStr);
|
Result->SetStringField(TEXT("newValue"), NewValueStr);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -1470,14 +1448,16 @@ public:
|
|||||||
|
|
||||||
if (!MaterialFunction.IsEmpty())
|
if (!MaterialFunction.IsEmpty())
|
||||||
{
|
{
|
||||||
MatFunc = UMCPAssetFinder::LoadAsset<UMaterialFunction>(MaterialFunction, Result);
|
MCPAssets<UMaterialFunction> MFAssets;
|
||||||
if (!MatFunc) return;
|
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MatFunc = MFAssets.Object();
|
||||||
AssetDisplayName = MatFunc->GetName();
|
AssetDisplayName = MatFunc->GetName();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> MatAssets;
|
||||||
if (!MaterialObj) return;
|
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
MaterialObj = MatAssets.Object();
|
||||||
AssetDisplayName = MaterialObj->GetName();
|
AssetDisplayName = MaterialObj->GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1510,12 +1490,8 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would move node '%s' to (%d, %d) in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: [DRY RUN] Would move node '%s' to (%d, %d) in '%s'"),
|
||||||
*Node, PosX, PosY, *AssetDisplayName);
|
*Node, PosX, PosY, *AssetDisplayName);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetNumberField(TEXT("posX"), PosX);
|
|
||||||
Result->SetNumberField(TEXT("posY"), PosY);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1540,11 +1516,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Moved node '%s' to (%d, %d) in '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Moved node '%s' to (%d, %d) in '%s' (saved: %s)"),
|
||||||
*Node, PosX, PosY, *AssetDisplayName, bSaved ? TEXT("true") : TEXT("false"));
|
*Node, PosX, PosY, *AssetDisplayName, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
Result->SetStringField(TEXT("material"), AssetDisplayName);
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetNumberField(TEXT("posX"), PosX);
|
|
||||||
Result->SetNumberField(TEXT("posY"), PosY);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1581,13 +1553,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if asset already exists
|
// Check if asset already exists
|
||||||
FString FullAssetPath = PackagePath / Name;
|
MCPAssets<UMaterialFunction> ExistCheck;
|
||||||
if (UMCPAssetFinder::FindAsset(UMaterialFunction::StaticClass(), Name) || UMCPAssetFinder::FindAsset(UMaterialFunction::StaticClass(), FullAssetPath))
|
if (!ExistCheck.Exact(Name).Errors(Result).EAny().Info()) return;
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(
|
|
||||||
TEXT("Material Function '%s' already exists. Use a different name or delete the existing asset first."),
|
|
||||||
*Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Material Function '%s' in '%s'"), *Name, *PackagePath);
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Creating Material Function '%s' in '%s'"), *Name, *PackagePath);
|
||||||
|
|
||||||
@@ -1620,13 +1587,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Material Function '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Created Material Function '%s' (saved: %s)"),
|
||||||
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
*Name, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("name"), Name);
|
|
||||||
Result->SetStringField(TEXT("path"), MF->GetPathName());
|
Result->SetStringField(TEXT("path"), MF->GetPathName());
|
||||||
if (!Description.IsEmpty())
|
|
||||||
{
|
|
||||||
Result->SetStringField(TEXT("description"), Description);
|
|
||||||
}
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -61,60 +61,24 @@ public:
|
|||||||
bool bIncludeMaterials = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("material");
|
bool bIncludeMaterials = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("material");
|
||||||
bool bIncludeInstances = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("instance");
|
bool bIncludeInstances = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("instance");
|
||||||
|
|
||||||
|
MCPAssets<UMaterial> Assets;
|
||||||
|
if (bIncludeMaterials) Assets.Scan(UMaterial::StaticClass());
|
||||||
|
if (bIncludeInstances) Assets.Scan(UMaterialInstanceConstant::StaticClass());
|
||||||
|
Assets.Substring(Filter).NoDerived().Info();
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Entries;
|
TArray<TSharedPtr<FJsonValue>> Entries;
|
||||||
|
for (const FAssetData& Asset : Assets.AllData())
|
||||||
if (bIncludeMaterials)
|
|
||||||
{
|
{
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UMaterial::StaticClass()))
|
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
||||||
{
|
Entry->SetStringField(TEXT("name"), Asset.AssetName.ToString());
|
||||||
FString Name = Asset.AssetName.ToString();
|
Entry->SetStringField(TEXT("path"), Asset.PackageName.ToString());
|
||||||
FString Path = Asset.PackageName.ToString();
|
Entry->SetStringField(TEXT("type"),
|
||||||
|
Asset.AssetClassPath.GetAssetName() == TEXT("MaterialInstanceConstant")
|
||||||
if (!Filter.IsEmpty())
|
? TEXT("MaterialInstance") : TEXT("Material"));
|
||||||
{
|
Entries.Add(MakeShared<FJsonValueObject>(Entry));
|
||||||
if (!Name.Contains(Filter, ESearchCase::IgnoreCase) &&
|
|
||||||
!Path.Contains(Filter, ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
|
||||||
Entry->SetStringField(TEXT("name"), Name);
|
|
||||||
Entry->SetStringField(TEXT("path"), Path);
|
|
||||||
Entry->SetStringField(TEXT("type"), TEXT("Material"));
|
|
||||||
Entries.Add(MakeShared<FJsonValueObject>(Entry));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bIncludeInstances)
|
|
||||||
{
|
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UMaterialInstanceConstant::StaticClass()))
|
|
||||||
{
|
|
||||||
FString Name = Asset.AssetName.ToString();
|
|
||||||
FString Path = Asset.PackageName.ToString();
|
|
||||||
|
|
||||||
if (!Filter.IsEmpty())
|
|
||||||
{
|
|
||||||
if (!Name.Contains(Filter, ESearchCase::IgnoreCase) &&
|
|
||||||
!Path.Contains(Filter, ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
|
||||||
Entry->SetStringField(TEXT("name"), Name);
|
|
||||||
Entry->SetStringField(TEXT("path"), Path);
|
|
||||||
Entry->SetStringField(TEXT("type"), TEXT("MaterialInstance"));
|
|
||||||
Entries.Add(MakeShared<FJsonValueObject>(Entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32 Total = UMCPAssetFinder::GetAssets(UMaterial::StaticClass()).Num() + UMCPAssetFinder::GetAssets(UMaterialInstanceConstant::StaticClass()).Num();
|
|
||||||
|
|
||||||
Result->SetNumberField(TEXT("count"), Entries.Num());
|
Result->SetNumberField(TEXT("count"), Entries.Num());
|
||||||
Result->SetNumberField(TEXT("total"), Total);
|
|
||||||
Result->SetArrayField(TEXT("materials"), Entries);
|
Result->SetArrayField(TEXT("materials"), Entries);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -141,10 +105,14 @@ public:
|
|||||||
{
|
{
|
||||||
FString DecodedName = MCPUtils::UrlDecode(Material);
|
FString DecodedName = MCPUtils::UrlDecode(Material);
|
||||||
|
|
||||||
// Try loading as UMaterial first
|
// Try loading as UMaterial or UMaterialInstanceConstant
|
||||||
FString LoadError;
|
MCPAssets<UMaterialInterface> Assets;
|
||||||
UMaterial* MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(DecodedName, LoadError);
|
Assets.Scan(UMaterial::StaticClass());
|
||||||
if (MaterialObj)
|
Assets.Scan(UMaterialInstanceConstant::StaticClass());
|
||||||
|
if (!Assets.Exact(DecodedName).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterialInterface* LoadedObj = Assets.Object();
|
||||||
|
|
||||||
|
if (UMaterial* MaterialObj = Cast<UMaterial>(LoadedObj))
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterial — loaded material '%s'"), *MaterialObj->GetName());
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterial — loaded material '%s'"), *MaterialObj->GetName());
|
||||||
|
|
||||||
@@ -296,10 +264,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try loading as MaterialInstance
|
if (UMaterialInstanceConstant* MI = Cast<UMaterialInstanceConstant>(LoadedObj))
|
||||||
FString MILoadError;
|
|
||||||
UMaterialInstanceConstant* MI = UMCPAssetFinder::LoadAsset<UMaterialInstanceConstant>(DecodedName, MILoadError);
|
|
||||||
if (MI)
|
|
||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterial — loaded material instance '%s'"), *MI->GetName());
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterial — loaded material instance '%s'"), *MI->GetName());
|
||||||
|
|
||||||
@@ -396,8 +361,9 @@ public:
|
|||||||
{
|
{
|
||||||
FString DecodedName = MCPUtils::UrlDecode(Material);
|
FString DecodedName = MCPUtils::UrlDecode(Material);
|
||||||
|
|
||||||
UMaterial* MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(DecodedName, Result);
|
MCPAssets<UMaterial> Assets;
|
||||||
if (!MaterialObj) return;
|
if (!Assets.Exact(DecodedName).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterial* MaterialObj = Assets.Object();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterialGraph — material '%s'"), *MaterialObj->GetName());
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterialGraph — material '%s'"), *MaterialObj->GetName());
|
||||||
|
|
||||||
@@ -451,8 +417,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UMaterial* MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> Assets;
|
||||||
if (!MaterialObj) return;
|
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterial* MaterialObj = Assets.Object();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: DescribeMaterial — '%s'"), *MaterialObj->GetName());
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: DescribeMaterial — '%s'"), *MaterialObj->GetName());
|
||||||
|
|
||||||
@@ -613,7 +580,6 @@ public:
|
|||||||
InputDescriptions.Add(MakeShared<FJsonValueObject>(InputObj));
|
InputDescriptions.Add(MakeShared<FJsonValueObject>(InputObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), MaterialObj->GetName());
|
Result->SetStringField(TEXT("material"), MaterialObj->GetName());
|
||||||
Result->SetStringField(TEXT("materialPath"), MaterialObj->GetPathName());
|
Result->SetStringField(TEXT("materialPath"), MaterialObj->GetPathName());
|
||||||
Result->SetArrayField(TEXT("inputs"), InputDescriptions);
|
Result->SetArrayField(TEXT("inputs"), InputDescriptions);
|
||||||
@@ -668,7 +634,10 @@ public:
|
|||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
|
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UMaterial::StaticClass()))
|
MCPAssets<UMaterial> AllMaterials;
|
||||||
|
AllMaterials.Info();
|
||||||
|
|
||||||
|
for (const FAssetData& Asset : AllMaterials.AllData())
|
||||||
{
|
{
|
||||||
if (Results.Num() >= MaxResults) break;
|
if (Results.Num() >= MaxResults) break;
|
||||||
|
|
||||||
@@ -757,27 +726,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Try to find the material's package path
|
// Try to find the material's package path (search both Material and MaterialInstance)
|
||||||
FString PackagePath;
|
MCPAssets<UMaterial> Assets;
|
||||||
FAssetData* MatAsset = UMCPAssetFinder::FindAsset(UMaterial::StaticClass(), Material);
|
Assets.Scan<UMaterial>().Scan<UMaterialInstanceConstant>();
|
||||||
if (MatAsset)
|
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Info()) return;
|
||||||
{
|
FString PackagePath = Assets.OneData().PackageName.ToString();
|
||||||
PackagePath = MatAsset->PackageName.ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Try material instance
|
|
||||||
FAssetData* MIAsset = UMCPAssetFinder::FindAsset(UMaterialInstanceConstant::StaticClass(), Material);
|
|
||||||
if (MIAsset)
|
|
||||||
{
|
|
||||||
PackagePath = MIAsset->PackageName.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PackagePath.IsEmpty())
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Material '%s' not found. Use list_materials to see available assets."), *Material));
|
|
||||||
}
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: FindMaterialReferences — '%s' (package: %s)"), *Material, *PackagePath);
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: FindMaterialReferences — '%s' (package: %s)"), *Material, *PackagePath);
|
||||||
|
|
||||||
@@ -795,8 +748,6 @@ public:
|
|||||||
RefArray.Add(MakeShared<FJsonValueString>(RefStr));
|
RefArray.Add(MakeShared<FJsonValueString>(RefStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("material"), Material);
|
|
||||||
Result->SetStringField(TEXT("packagePath"), PackagePath);
|
Result->SetStringField(TEXT("packagePath"), PackagePath);
|
||||||
Result->SetNumberField(TEXT("totalReferencers"), RefArray.Num());
|
Result->SetNumberField(TEXT("totalReferencers"), RefArray.Num());
|
||||||
Result->SetArrayField(TEXT("referencers"), RefArray);
|
Result->SetArrayField(TEXT("referencers"), RefArray);
|
||||||
@@ -823,30 +774,19 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
MCPAssets<UMaterialFunction> Assets;
|
||||||
|
Assets.Substring(Filter).Info();
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Entries;
|
TArray<TSharedPtr<FJsonValue>> Entries;
|
||||||
|
for (const FAssetData& Asset : Assets.AllData())
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UMaterialFunction::StaticClass()))
|
|
||||||
{
|
{
|
||||||
FString Name = Asset.AssetName.ToString();
|
|
||||||
FString Path = Asset.PackageName.ToString();
|
|
||||||
|
|
||||||
if (!Filter.IsEmpty())
|
|
||||||
{
|
|
||||||
if (!Name.Contains(Filter, ESearchCase::IgnoreCase) &&
|
|
||||||
!Path.Contains(Filter, ESearchCase::IgnoreCase))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
TSharedRef<FJsonObject> Entry = MakeShared<FJsonObject>();
|
||||||
Entry->SetStringField(TEXT("name"), Name);
|
Entry->SetStringField(TEXT("name"), Asset.AssetName.ToString());
|
||||||
Entry->SetStringField(TEXT("path"), Path);
|
Entry->SetStringField(TEXT("path"), Asset.PackageName.ToString());
|
||||||
Entries.Add(MakeShared<FJsonValueObject>(Entry));
|
Entries.Add(MakeShared<FJsonValueObject>(Entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetNumberField(TEXT("count"), Entries.Num());
|
Result->SetNumberField(TEXT("count"), Entries.Num());
|
||||||
Result->SetNumberField(TEXT("total"), UMCPAssetFinder::GetAssets(UMaterialFunction::StaticClass()).Num());
|
|
||||||
Result->SetArrayField(TEXT("functions"), Entries);
|
Result->SetArrayField(TEXT("functions"), Entries);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -873,8 +813,9 @@ public:
|
|||||||
{
|
{
|
||||||
FString DecodedName = MCPUtils::UrlDecode(MaterialFunction);
|
FString DecodedName = MCPUtils::UrlDecode(MaterialFunction);
|
||||||
|
|
||||||
UMaterialFunction* MF = UMCPAssetFinder::LoadAsset<UMaterialFunction>(DecodedName, Result);
|
MCPAssets<UMaterialFunction> Assets;
|
||||||
if (!MF) return;
|
if (!Assets.Exact(DecodedName).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterialFunction* MF = Assets.Object();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterialFunction — '%s'"), *MF->GetName());
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: GetMaterialFunction — '%s'"), *MF->GetName());
|
||||||
|
|
||||||
@@ -962,8 +903,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load material
|
// Load material
|
||||||
UMaterial* MaterialObj = UMCPAssetFinder::LoadAsset<UMaterial>(Material, Result);
|
MCPAssets<UMaterial> Assets;
|
||||||
if (!MaterialObj) return;
|
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UMaterial* MaterialObj = Assets.Object();
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Validating material '%s'"), *MaterialObj->GetName());
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Validating material '%s'"), *MaterialObj->GetName());
|
||||||
|
|
||||||
|
|||||||
@@ -90,12 +90,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
int32 SuccessCount = 0;
|
int32 SuccessCount = 0;
|
||||||
@@ -113,8 +110,6 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetStringField(TEXT("nodeId"), Entry.Node);
|
|
||||||
|
|
||||||
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
|
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
|
||||||
if (!Node)
|
if (!Node)
|
||||||
{
|
{
|
||||||
@@ -126,7 +121,6 @@ public:
|
|||||||
int32 OldY = Node->NodePosY;
|
int32 OldY = Node->NodePosY;
|
||||||
Node->NodePosX = Entry.X;
|
Node->NodePosX = Entry.X;
|
||||||
Node->NodePosY = Entry.Y;
|
Node->NodePosY = Entry.Y;
|
||||||
EntryResult->SetBoolField(TEXT("success"), true);
|
|
||||||
EntryResult->SetNumberField(TEXT("oldX"), OldX);
|
EntryResult->SetNumberField(TEXT("oldX"), OldX);
|
||||||
EntryResult->SetNumberField(TEXT("oldY"), OldY);
|
EntryResult->SetNumberField(TEXT("oldY"), OldY);
|
||||||
EntryResult->SetNumberField(TEXT("newX"), Node->NodePosX);
|
EntryResult->SetNumberField(TEXT("newX"), Node->NodePosX);
|
||||||
@@ -139,8 +133,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: MoveNode — %d/%d succeeded"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: MoveNode — %d/%d succeeded"),
|
||||||
SuccessCount, Nodes.Array.Num());
|
SuccessCount, Nodes.Array.Num());
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("movedCount"), SuccessCount);
|
Result->SetNumberField(TEXT("movedCount"), SuccessCount);
|
||||||
Result->SetNumberField(TEXT("totalRequested"), Nodes.Array.Num());
|
Result->SetNumberField(TEXT("totalRequested"), Nodes.Array.Num());
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
@@ -182,12 +174,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the target graph
|
// Find the target graph
|
||||||
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
||||||
@@ -294,9 +283,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Duplicated %d node(s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Duplicated %d node(s)"),
|
||||||
DuplicatedNodes.Num());
|
DuplicatedNodes.Num());
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("graph"), DecodedGraphName);
|
|
||||||
Result->SetNumberField(TEXT("duplicatedCount"), DuplicatedNodes.Num());
|
Result->SetNumberField(TEXT("duplicatedCount"), DuplicatedNodes.Num());
|
||||||
Result->SetArrayField(TEXT("nodes"), DuplicatedNodes);
|
Result->SetArrayField(TEXT("nodes"), DuplicatedNodes);
|
||||||
|
|
||||||
@@ -358,12 +344,9 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the target graph
|
// Find the target graph
|
||||||
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
||||||
@@ -408,8 +391,6 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetStringField(TEXT("actionName"), Entry.ActionName);
|
|
||||||
|
|
||||||
// Find the spawner by exact full name
|
// Find the spawner by exact full name
|
||||||
TArray<UBlueprintNodeSpawner*> Matches = MCPUtils::SearchNodeSpawners(Entry.ActionName, 0, /*ExactMatch=*/true, TargetGraph);
|
TArray<UBlueprintNodeSpawner*> Matches = MCPUtils::SearchNodeSpawners(Entry.ActionName, 0, /*ExactMatch=*/true, TargetGraph);
|
||||||
if (Matches.Num() == 0)
|
if (Matches.Num() == 0)
|
||||||
@@ -455,7 +436,6 @@ public:
|
|||||||
// Serialize result
|
// Serialize result
|
||||||
TSharedPtr<FJsonObject> NodeState = MCPUtils::SerializeNode(NewNode);
|
TSharedPtr<FJsonObject> NodeState = MCPUtils::SerializeNode(NewNode);
|
||||||
|
|
||||||
EntryResult->SetBoolField(TEXT("success"), true);
|
|
||||||
EntryResult->SetStringField(TEXT("nodeId"), NewNode->NodeGuid.ToString());
|
EntryResult->SetStringField(TEXT("nodeId"), NewNode->NodeGuid.ToString());
|
||||||
EntryResult->SetStringField(TEXT("nodeClass"), NewNode->GetClass()->GetName());
|
EntryResult->SetStringField(TEXT("nodeClass"), NewNode->GetClass()->GetName());
|
||||||
EntryResult->SetStringField(TEXT("nodeTitle"), NewNode->GetNodeTitle(ENodeTitleType::ListView).ToString());
|
EntryResult->SetStringField(TEXT("nodeTitle"), NewNode->GetNodeTitle(ENodeTitleType::ListView).ToString());
|
||||||
@@ -471,9 +451,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: SpawnNode — %d/%d succeeded in graph '%s' of '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: SpawnNode — %d/%d succeeded in graph '%s' of '%s'"),
|
||||||
SuccessCount, Nodes.Array.Num(), *DecodedGraphName, *Blueprint);
|
SuccessCount, Nodes.Array.Num(), *DecodedGraphName, *Blueprint);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("graph"), DecodedGraphName);
|
|
||||||
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
||||||
Result->SetNumberField(TEXT("totalCount"), Nodes.Array.Num());
|
Result->SetNumberField(TEXT("totalCount"), Nodes.Array.Num());
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
@@ -504,12 +481,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node);
|
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node);
|
||||||
if (!FoundNode)
|
if (!FoundNode)
|
||||||
@@ -517,9 +491,6 @@ public:
|
|||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' not found"), *Node));
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Node '%s' not found"), *Node));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("comment"), FoundNode->NodeComment);
|
Result->SetStringField(TEXT("comment"), FoundNode->NodeComment);
|
||||||
Result->SetBoolField(TEXT("commentBubbleVisible"), FoundNode->bCommentBubbleVisible);
|
Result->SetBoolField(TEXT("commentBubbleVisible"), FoundNode->bCommentBubbleVisible);
|
||||||
}
|
}
|
||||||
@@ -552,12 +523,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node);
|
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node);
|
||||||
if (!FoundNode)
|
if (!FoundNode)
|
||||||
@@ -580,11 +548,7 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set comment on node '%s' in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set comment on node '%s' in '%s'"),
|
||||||
*Node, *Blueprint);
|
*Node, *Blueprint);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("oldComment"), OldComment);
|
Result->SetStringField(TEXT("oldComment"), OldComment);
|
||||||
Result->SetStringField(TEXT("newComment"), Comment);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -613,12 +577,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
UEdGraph* Graph = nullptr;
|
UEdGraph* Graph = nullptr;
|
||||||
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node, &Graph);
|
UEdGraphNode* FoundNode = MCPUtils::FindNodeByGuid(BP, Node, &Graph);
|
||||||
@@ -671,9 +632,6 @@ public:
|
|||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Node deleted"));
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Node deleted"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("nodeClass"), NodeClass);
|
Result->SetStringField(TEXT("nodeClass"), NodeClass);
|
||||||
Result->SetStringField(TEXT("nodeTitle"), NodeTitle);
|
Result->SetStringField(TEXT("nodeTitle"), NodeTitle);
|
||||||
Result->SetStringField(TEXT("graph"), GraphName);
|
Result->SetStringField(TEXT("graph"), GraphName);
|
||||||
@@ -712,12 +670,9 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the new class — try several search strategies
|
// Find the new class — try several search strategies
|
||||||
UClass* NewClassPtr = nullptr;
|
UClass* NewClassPtr = nullptr;
|
||||||
@@ -913,8 +868,6 @@ public:
|
|||||||
|
|
||||||
if (DryRun)
|
if (DryRun)
|
||||||
{
|
{
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("wouldReplaceCount"), ReplacedCount);
|
Result->SetNumberField(TEXT("wouldReplaceCount"), ReplacedCount);
|
||||||
Result->SetNumberField(TEXT("connectionsAtRisk"), BrokenConnections.Num());
|
Result->SetNumberField(TEXT("connectionsAtRisk"), BrokenConnections.Num());
|
||||||
Result->SetArrayField(TEXT("connectionsAtRisk"), BrokenConnections);
|
Result->SetArrayField(TEXT("connectionsAtRisk"), BrokenConnections);
|
||||||
@@ -927,14 +880,12 @@ public:
|
|||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Replaced %d function call(s)"), ReplacedCount);
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Replaced %d function call(s)"), ReplacedCount);
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("replacedCount"), ReplacedCount);
|
Result->SetNumberField(TEXT("replacedCount"), ReplacedCount);
|
||||||
Result->SetNumberField(TEXT("brokenConnectionCount"), BrokenConnections.Num());
|
Result->SetNumberField(TEXT("brokenConnectionCount"), BrokenConnections.Num());
|
||||||
Result->SetArrayField(TEXT("brokenConnections"), BrokenConnections);
|
Result->SetArrayField(TEXT("brokenConnections"), BrokenConnections);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("replacedCount"), 0);
|
Result->SetNumberField(TEXT("replacedCount"), 0);
|
||||||
Result->SetStringField(TEXT("message"), FString::Printf(
|
Result->SetStringField(TEXT("message"), FString::Printf(
|
||||||
TEXT("No function call nodes found targeting class '%s'"), *OldClass));
|
TEXT("No function call nodes found targeting class '%s'"), *OldClass));
|
||||||
@@ -964,12 +915,9 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count graphs and nodes before refresh
|
// Count graphs and nodes before refresh
|
||||||
TArray<UEdGraph*> AllGraphs;
|
TArray<UEdGraph*> AllGraphs;
|
||||||
@@ -1053,8 +1001,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("graphCount"), GraphCount);
|
Result->SetNumberField(TEXT("graphCount"), GraphCount);
|
||||||
Result->SetNumberField(TEXT("nodeCount"), NodeCount);
|
Result->SetNumberField(TEXT("nodeCount"), NodeCount);
|
||||||
Result->SetNumberField(TEXT("orphanedPinsRemoved"), OrphanedPinsRemoved);
|
Result->SetNumberField(TEXT("orphanedPinsRemoved"), OrphanedPinsRemoved);
|
||||||
@@ -1092,12 +1038,9 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find node
|
// Find node
|
||||||
UEdGraph* Graph = nullptr;
|
UEdGraph* Graph = nullptr;
|
||||||
@@ -1281,9 +1224,6 @@ public:
|
|||||||
// Return updated node state
|
// Return updated node state
|
||||||
TSharedPtr<FJsonObject> UpdatedNodeState = MCPUtils::SerializeNode(FoundNode);
|
TSharedPtr<FJsonObject> UpdatedNodeState = MCPUtils::SerializeNode(FoundNode);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), Node);
|
|
||||||
Result->SetStringField(TEXT("newStructType"), NewStruct->GetName());
|
Result->SetStringField(TEXT("newStructType"), NewStruct->GetName());
|
||||||
Result->SetStringField(TEXT("nodeClass"), FoundNode->GetClass()->GetName());
|
Result->SetStringField(TEXT("nodeClass"), FoundNode->GetClass()->GetName());
|
||||||
Result->SetNumberField(TEXT("reconnected"), Reconnected);
|
Result->SetNumberField(TEXT("reconnected"), Reconnected);
|
||||||
@@ -1325,12 +1265,9 @@ public:
|
|||||||
{
|
{
|
||||||
|
|
||||||
// Load Blueprint
|
// Load Blueprint
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BP->GeneratedClass)
|
if (!BP->GeneratedClass)
|
||||||
{
|
{
|
||||||
@@ -1377,11 +1314,12 @@ public:
|
|||||||
// Try loading as a Blueprint asset
|
// Try loading as a Blueprint asset
|
||||||
if (!ResolvedClass)
|
if (!ResolvedClass)
|
||||||
{
|
{
|
||||||
FString BPLoadError;
|
MCPAssets<UBlueprint> ValueAssets;
|
||||||
UBlueprint* ValueBP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Value, BPLoadError);
|
if (!ValueAssets.Exact(Value).AllContent().Errors(Result).ETwo().Load()) return;
|
||||||
if (ValueBP && ValueBP->GeneratedClass)
|
if (!ValueAssets.Objects().IsEmpty())
|
||||||
{
|
{
|
||||||
ResolvedClass = ValueBP->GeneratedClass;
|
if (ValueAssets.Object()->GeneratedClass)
|
||||||
|
ResolvedClass = ValueAssets.Object()->GeneratedClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1417,17 +1355,10 @@ public:
|
|||||||
UObject* ResolvedObj = nullptr;
|
UObject* ResolvedObj = nullptr;
|
||||||
|
|
||||||
// Try loading as a Blueprint asset
|
// Try loading as a Blueprint asset
|
||||||
FString ObjLoadError;
|
MCPAssets<UBlueprint> ValueAssets;
|
||||||
UBlueprint* ValueBP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Value, ObjLoadError);
|
if (!ValueAssets.Exact(Value).AllContent().Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (ValueBP && ValueBP->GeneratedClass)
|
if (ValueAssets.Object()->GeneratedClass)
|
||||||
{
|
ResolvedObj = ValueAssets.Object()->GeneratedClass->GetDefaultObject();
|
||||||
ResolvedObj = ValueBP->GeneratedClass->GetDefaultObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ResolvedObj)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Could not resolve '%s' to an object"), *Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjProp->SetPropertyValue_InContainer(CDO, ResolvedObj);
|
ObjProp->SetPropertyValue_InContainer(CDO, ResolvedObj);
|
||||||
ActualNewValue = ResolvedObj->GetName();
|
ActualNewValue = ResolvedObj->GetName();
|
||||||
@@ -1465,9 +1396,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set '%s.%s' from '%s' to '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Set '%s.%s' from '%s' to '%s' (saved: %s)"),
|
||||||
*Blueprint, *Property, *OldValue, *ActualNewValue, bSaved ? TEXT("true") : TEXT("false"));
|
*Blueprint, *Property, *OldValue, *ActualNewValue, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("property"), Property);
|
|
||||||
Result->SetStringField(TEXT("oldValue"), OldValue);
|
Result->SetStringField(TEXT("oldValue"), OldValue);
|
||||||
Result->SetStringField(TEXT("newValue"), ActualNewValue);
|
Result->SetStringField(TEXT("newValue"), ActualNewValue);
|
||||||
Result->SetStringField(TEXT("propertyType"), Prop->GetCPPType());
|
Result->SetStringField(TEXT("propertyType"), Prop->GetCPPType());
|
||||||
@@ -1512,8 +1440,9 @@ public:
|
|||||||
UEdGraph* GraphFilter = nullptr;
|
UEdGraph* GraphFilter = nullptr;
|
||||||
if (!Blueprint.IsEmpty() && !Graph.IsEmpty())
|
if (!Blueprint.IsEmpty() && !Graph.IsEmpty())
|
||||||
{
|
{
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, Result);
|
MCPAssets<UBlueprint> BPAssets;
|
||||||
if (!BP) return;
|
if (!BPAssets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UBlueprint* BP = BPAssets.Object();
|
||||||
|
|
||||||
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
||||||
TArray<UEdGraph*> AllGraphs;
|
TArray<UEdGraph*> AllGraphs;
|
||||||
@@ -1540,7 +1469,6 @@ public:
|
|||||||
ResultArray.Add(MakeShared<FJsonValueString>(MCPUtils::NodeSpawnerFullName(Spawner)));
|
ResultArray.Add(MakeShared<FJsonValueString>(MCPUtils::NodeSpawnerFullName(Spawner)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetNumberField(TEXT("count"), ResultArray.Num());
|
Result->SetNumberField(TEXT("count"), ResultArray.Num());
|
||||||
Result->SetArrayField(TEXT("results"), ResultArray);
|
Result->SetArrayField(TEXT("results"), ResultArray);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,13 +45,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve the new type using the shared resolver (supports primitives, structs, enums, and object references)
|
// Resolve the new type using the shared resolver (supports primitives, structs, enums, and object references)
|
||||||
FEdGraphPinType NewPinType;
|
FEdGraphPinType NewPinType;
|
||||||
@@ -193,10 +189,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("functionName"), FunctionName);
|
|
||||||
Result->SetStringField(TEXT("paramName"), ParamName);
|
|
||||||
Result->SetStringField(TEXT("newType"), NewType);
|
|
||||||
Result->SetStringField(TEXT("nodeType"), FoundNodeType);
|
Result->SetStringField(TEXT("nodeType"), FoundNodeType);
|
||||||
Result->SetStringField(TEXT("nodeId"), EntryNode->NodeGuid.ToString());
|
Result->SetStringField(TEXT("nodeId"), EntryNode->NodeGuid.ToString());
|
||||||
Result->SetNumberField(TEXT("connectionsAtRisk"), AffectedPins.Num());
|
Result->SetNumberField(TEXT("connectionsAtRisk"), AffectedPins.Num());
|
||||||
@@ -225,11 +217,6 @@ public:
|
|||||||
// Serialize the updated entry node state
|
// Serialize the updated entry node state
|
||||||
TSharedPtr<FJsonObject> UpdatedNodeState = MCPUtils::SerializeNode(EntryNode);
|
TSharedPtr<FJsonObject> UpdatedNodeState = MCPUtils::SerializeNode(EntryNode);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("functionName"), FunctionName);
|
|
||||||
Result->SetStringField(TEXT("paramName"), ParamName);
|
|
||||||
Result->SetStringField(TEXT("newType"), NewType);
|
|
||||||
Result->SetStringField(TEXT("nodeType"), FoundNodeType);
|
Result->SetStringField(TEXT("nodeType"), FoundNodeType);
|
||||||
Result->SetStringField(TEXT("nodeId"), EntryNode->NodeGuid.ToString());
|
Result->SetStringField(TEXT("nodeId"), EntryNode->NodeGuid.ToString());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -266,13 +253,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the entry node
|
// Find the entry node
|
||||||
UK2Node_EditablePinBase* EntryNode = nullptr;
|
UK2Node_EditablePinBase* EntryNode = nullptr;
|
||||||
@@ -402,10 +385,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Parameter removed, save %s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Parameter removed, save %s"),
|
||||||
bSaved ? TEXT("succeeded") : TEXT("failed"));
|
bSaved ? TEXT("succeeded") : TEXT("failed"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("functionName"), FunctionName);
|
|
||||||
Result->SetStringField(TEXT("paramName"), ParamName);
|
|
||||||
Result->SetStringField(TEXT("nodeType"), FoundNodeType);
|
Result->SetStringField(TEXT("nodeType"), FoundNodeType);
|
||||||
Result->SetStringField(TEXT("nodeId"), EntryNode->NodeGuid.ToString());
|
Result->SetStringField(TEXT("nodeId"), EntryNode->NodeGuid.ToString());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -441,13 +420,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resolve param type
|
// Resolve param type
|
||||||
FEdGraphPinType PinType;
|
FEdGraphPinType PinType;
|
||||||
@@ -595,11 +570,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added parameter '%s' to '%s' in '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added parameter '%s' to '%s' in '%s' (saved: %s)"),
|
||||||
*ParamName, *FunctionName, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
*ParamName, *FunctionName, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("functionName"), FunctionName);
|
|
||||||
Result->SetStringField(TEXT("paramName"), ParamName);
|
|
||||||
Result->SetStringField(TEXT("paramType"), ParamType);
|
|
||||||
Result->SetStringField(TEXT("nodeType"), NodeType);
|
Result->SetStringField(TEXT("nodeType"), NodeType);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "MCPAssetFinder.h"
|
#include "MCPAssetFinder.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
#include "Engine/Blueprint.h"
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
#include "EdGraph/EdGraph.h"
|
#include "EdGraph/EdGraph.h"
|
||||||
#include "EdGraph/EdGraphNode.h"
|
#include "EdGraph/EdGraphNode.h"
|
||||||
#include "EdGraph/EdGraphPin.h"
|
#include "EdGraph/EdGraphPin.h"
|
||||||
@@ -69,17 +70,10 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetStringField(TEXT("blueprint"), Entry.Blueprint);
|
MCPAssets<UBlueprint> Assets;
|
||||||
EntryResult->SetStringField(TEXT("nodeId"), Entry.Node);
|
if (!Assets.Scan<UBlueprint>().Scan<UWorld>().Exact(Entry.Blueprint).Errors(&*EntryResult).ENone().ETwo().Load())
|
||||||
EntryResult->SetStringField(TEXT("pinName"), Entry.PinName);
|
|
||||||
|
|
||||||
FString LoadError;
|
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Entry.Blueprint, LoadError);
|
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
EntryResult->SetStringField(TEXT("error"), LoadError);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
UBlueprint* BP = Assets.Object();
|
||||||
|
|
||||||
UEdGraph* Graph = nullptr;
|
UEdGraph* Graph = nullptr;
|
||||||
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node, &Graph);
|
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node, &Graph);
|
||||||
@@ -117,9 +111,7 @@ public:
|
|||||||
FString OldValue = Pin->DefaultValue;
|
FString OldValue = Pin->DefaultValue;
|
||||||
Pin->DefaultValue = Entry.Value;
|
Pin->DefaultValue = Entry.Value;
|
||||||
|
|
||||||
EntryResult->SetBoolField(TEXT("success"), true);
|
|
||||||
EntryResult->SetStringField(TEXT("oldValue"), OldValue);
|
EntryResult->SetStringField(TEXT("oldValue"), OldValue);
|
||||||
EntryResult->SetStringField(TEXT("newValue"), Pin->DefaultValue);
|
|
||||||
SuccessCount++;
|
SuccessCount++;
|
||||||
ModifiedNodes.Add(Node);
|
ModifiedNodes.Add(Node);
|
||||||
ModifiedBlueprints.Add(BP);
|
ModifiedBlueprints.Add(BP);
|
||||||
@@ -138,7 +130,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: SetPinDefault — %d/%d succeeded"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: SetPinDefault — %d/%d succeeded"),
|
||||||
SuccessCount, Pins.Array.Num());
|
SuccessCount, Pins.Array.Num());
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
||||||
Result->SetNumberField(TEXT("totalCount"), Pins.Array.Num());
|
Result->SetNumberField(TEXT("totalCount"), Pins.Array.Num());
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
@@ -188,12 +179,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
int32 SuccessCount = 0;
|
int32 SuccessCount = 0;
|
||||||
@@ -211,11 +199,6 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetStringField(TEXT("sourceNodeId"), Entry.SourceNode);
|
|
||||||
EntryResult->SetStringField(TEXT("sourcePinName"), Entry.SourcePinName);
|
|
||||||
EntryResult->SetStringField(TEXT("targetNodeId"), Entry.TargetNode);
|
|
||||||
EntryResult->SetStringField(TEXT("targetPinName"), Entry.TargetPinName);
|
|
||||||
|
|
||||||
UEdGraph* SourceGraph = nullptr;
|
UEdGraph* SourceGraph = nullptr;
|
||||||
UEdGraphNode* SourceNode = MCPUtils::FindNodeByGuid(BP, Entry.SourceNode, &SourceGraph);
|
UEdGraphNode* SourceNode = MCPUtils::FindNodeByGuid(BP, Entry.SourceNode, &SourceGraph);
|
||||||
if (!SourceNode)
|
if (!SourceNode)
|
||||||
@@ -262,7 +245,6 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetBoolField(TEXT("success"), true);
|
|
||||||
SuccessCount++;
|
SuccessCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,9 +255,6 @@ public:
|
|||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: ConnectPins — %d/%d succeeded in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: ConnectPins — %d/%d succeeded in '%s'"),
|
||||||
SuccessCount, Connections.Array.Num(), *Blueprint);
|
SuccessCount, Connections.Array.Num(), *Blueprint);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
||||||
Result->SetNumberField(TEXT("totalCount"), Connections.Array.Num());
|
Result->SetNumberField(TEXT("totalCount"), Connections.Array.Num());
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
@@ -326,12 +305,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
int32 SuccessCount = 0;
|
int32 SuccessCount = 0;
|
||||||
@@ -350,9 +326,6 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetStringField(TEXT("nodeId"), Entry.Node);
|
|
||||||
EntryResult->SetStringField(TEXT("pinName"), Entry.PinName);
|
|
||||||
|
|
||||||
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
|
UEdGraphNode* Node = MCPUtils::FindNodeByGuid(BP, Entry.Node);
|
||||||
if (!Node)
|
if (!Node)
|
||||||
{
|
{
|
||||||
@@ -403,7 +376,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntryResult->SetBoolField(TEXT("success"), true);
|
|
||||||
EntryResult->SetNumberField(TEXT("disconnectedCount"), DisconnectedCount);
|
EntryResult->SetNumberField(TEXT("disconnectedCount"), DisconnectedCount);
|
||||||
SuccessCount++;
|
SuccessCount++;
|
||||||
TotalDisconnected += DisconnectedCount;
|
TotalDisconnected += DisconnectedCount;
|
||||||
@@ -417,8 +389,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: DisconnectPin — %d/%d succeeded, %d links broken in '%s'"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: DisconnectPin — %d/%d succeeded, %d links broken in '%s'"),
|
||||||
SuccessCount, Disconnections.Array.Num(), TotalDisconnected, *Blueprint);
|
SuccessCount, Disconnections.Array.Num(), TotalDisconnected, *Blueprint);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
Result->SetNumberField(TEXT("successCount"), SuccessCount);
|
||||||
Result->SetNumberField(TEXT("totalCount"), Disconnections.Array.Num());
|
Result->SetNumberField(TEXT("totalCount"), Disconnections.Array.Num());
|
||||||
Result->SetNumberField(TEXT("totalDisconnected"), TotalDisconnected);
|
Result->SetNumberField(TEXT("totalDisconnected"), TotalDisconnected);
|
||||||
|
|||||||
@@ -52,9 +52,14 @@ public:
|
|||||||
bool bIncludeRegular = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("regular");
|
bool bIncludeRegular = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("regular");
|
||||||
bool bIncludeLevel = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("level");
|
bool bIncludeLevel = Type.IsEmpty() || Type == TEXT("all") || Type == TEXT("level");
|
||||||
|
|
||||||
|
MCPAssets<UBlueprint> AllBlueprints;
|
||||||
|
AllBlueprints.Info();
|
||||||
|
MCPAssets<UWorld> AllWorlds;
|
||||||
|
AllWorlds.Info();
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Entries;
|
TArray<TSharedPtr<FJsonValue>> Entries;
|
||||||
if (bIncludeRegular)
|
if (bIncludeRegular)
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UBlueprint::StaticClass()))
|
for (const FAssetData& Asset : AllBlueprints.AllData())
|
||||||
{
|
{
|
||||||
FString Name = Asset.AssetName.ToString();
|
FString Name = Asset.AssetName.ToString();
|
||||||
FString Path = Asset.PackageName.ToString();
|
FString Path = Asset.PackageName.ToString();
|
||||||
@@ -94,7 +99,7 @@ public:
|
|||||||
|
|
||||||
// Also include level blueprints from maps
|
// Also include level blueprints from maps
|
||||||
if (bIncludeLevel)
|
if (bIncludeLevel)
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UWorld::StaticClass()))
|
for (const FAssetData& Asset : AllWorlds.AllData())
|
||||||
{
|
{
|
||||||
FString Name = Asset.AssetName.ToString();
|
FString Name = Asset.AssetName.ToString();
|
||||||
FString Path = Asset.PackageName.ToString();
|
FString Path = Asset.PackageName.ToString();
|
||||||
@@ -126,7 +131,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result->SetNumberField(TEXT("count"), Entries.Num());
|
Result->SetNumberField(TEXT("count"), Entries.Num());
|
||||||
Result->SetNumberField(TEXT("total"), UMCPAssetFinder::GetAssets(UBlueprint::StaticClass()).Num() + UMCPAssetFinder::GetAssets(UWorld::StaticClass()).Num());
|
Result->SetNumberField(TEXT("total"), AllBlueprints.AllData().Num() + AllWorlds.AllData().Num());
|
||||||
Result->SetArrayField(TEXT("blueprints"), Entries);
|
Result->SetArrayField(TEXT("blueprints"), Entries);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -151,10 +156,10 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, Result);
|
MCPAssets<UBlueprint> Assets;
|
||||||
if (!BP) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
|
||||||
TSharedRef<FJsonObject> Tmp = MCPUtils::SerializeBlueprint(BP);
|
TSharedRef<FJsonObject> Tmp = MCPUtils::SerializeBlueprint(Assets.Object());
|
||||||
MCPUtils::CopyJsonFields(&*Tmp, Result);
|
MCPUtils::CopyJsonFields(&*Tmp, Result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -185,12 +190,9 @@ public:
|
|||||||
// URL-decode graph name to handle spaces encoded as '+' or '%20'
|
// URL-decode graph name to handle spaces encoded as '+' or '%20'
|
||||||
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
FString DecodedGraphName = MCPUtils::UrlDecode(Graph);
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
TArray<UEdGraph*> AllGraphs;
|
TArray<UEdGraph*> AllGraphs;
|
||||||
BP->GetAllGraphs(AllGraphs);
|
BP->GetAllGraphs(AllGraphs);
|
||||||
@@ -310,8 +312,13 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MCPAssets<UBlueprint> AllBlueprints;
|
||||||
|
AllBlueprints.Info();
|
||||||
|
MCPAssets<UWorld> AllWorlds;
|
||||||
|
AllWorlds.Info();
|
||||||
|
|
||||||
TArray<TSharedPtr<FJsonValue>> Results;
|
TArray<TSharedPtr<FJsonValue>> Results;
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UBlueprint::StaticClass()))
|
for (const FAssetData& Asset : AllBlueprints.AllData())
|
||||||
{
|
{
|
||||||
if (Results.Num() >= EffectiveMaxResults) break;
|
if (Results.Num() >= EffectiveMaxResults) break;
|
||||||
|
|
||||||
@@ -328,7 +335,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Also search level blueprints
|
// Also search level blueprints
|
||||||
for (const FAssetData& MapAsset : UMCPAssetFinder::GetAssets(UWorld::StaticClass()))
|
for (const FAssetData& MapAsset : AllWorlds.AllData())
|
||||||
{
|
{
|
||||||
if (Results.Num() >= EffectiveMaxResults) break;
|
if (Results.Num() >= EffectiveMaxResults) break;
|
||||||
|
|
||||||
@@ -352,7 +359,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("query"), Query);
|
|
||||||
Result->SetNumberField(TEXT("resultCount"), Results.Num());
|
Result->SetNumberField(TEXT("resultCount"), Results.Num());
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
}
|
}
|
||||||
@@ -384,12 +390,9 @@ public:
|
|||||||
{
|
{
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: test-save requested for '%s'"), *Blueprint);
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: test-save requested for '%s'"), *Blueprint);
|
||||||
|
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Assets;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
if (!BP)
|
UBlueprint* BP = Assets.Object();
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: test-save — loaded '%s', GeneratedClass=%s"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: test-save — loaded '%s', GeneratedClass=%s"),
|
||||||
*BP->GetName(),
|
*BP->GetName(),
|
||||||
@@ -398,7 +401,6 @@ public:
|
|||||||
// Attempt save with NO modifications
|
// Attempt save with NO modifications
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("packagePath"), BP->GetPackage()->GetName());
|
Result->SetStringField(TEXT("packagePath"), BP->GetPackage()->GetName());
|
||||||
Result->SetBoolField(TEXT("hasGeneratedClass"), BP->GeneratedClass != nullptr);
|
Result->SetBoolField(TEXT("hasGeneratedClass"), BP->GeneratedClass != nullptr);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -435,8 +437,10 @@ public:
|
|||||||
Registry.GetReferencers(FName(*AssetPath), Referencers);
|
Registry.GetReferencers(FName(*AssetPath), Referencers);
|
||||||
|
|
||||||
// Build set of known Blueprint package names for filtering
|
// Build set of known Blueprint package names for filtering
|
||||||
|
MCPAssets<UBlueprint> AllBlueprints;
|
||||||
|
AllBlueprints.Info();
|
||||||
TSet<FString> BlueprintPackages;
|
TSet<FString> BlueprintPackages;
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UBlueprint::StaticClass()))
|
for (const FAssetData& Asset : AllBlueprints.AllData())
|
||||||
{
|
{
|
||||||
BlueprintPackages.Add(Asset.PackageName.ToString());
|
BlueprintPackages.Add(Asset.PackageName.ToString());
|
||||||
}
|
}
|
||||||
@@ -456,7 +460,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
||||||
Result->SetNumberField(TEXT("totalReferencers"), Referencers.Num());
|
Result->SetNumberField(TEXT("totalReferencers"), Referencers.Num());
|
||||||
Result->SetNumberField(TEXT("blueprintReferencerCount"), BPRefs.Num());
|
Result->SetNumberField(TEXT("blueprintReferencerCount"), BPRefs.Num());
|
||||||
Result->SetArrayField(TEXT("blueprintReferencers"), BPRefs);
|
Result->SetArrayField(TEXT("blueprintReferencers"), BPRefs);
|
||||||
@@ -680,8 +683,13 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MCPAssets<UBlueprint> AllBlueprints;
|
||||||
|
AllBlueprints.Info();
|
||||||
|
MCPAssets<UWorld> AllWorlds;
|
||||||
|
AllWorlds.Info();
|
||||||
|
|
||||||
// Search regular blueprints
|
// Search regular blueprints
|
||||||
for (const FAssetData& Asset : UMCPAssetFinder::GetAssets(UBlueprint::StaticClass()))
|
for (const FAssetData& Asset : AllBlueprints.AllData())
|
||||||
{
|
{
|
||||||
if (Results.Num() >= EffectiveMaxResults) break;
|
if (Results.Num() >= EffectiveMaxResults) break;
|
||||||
|
|
||||||
@@ -701,7 +709,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Search level blueprints from maps
|
// Search level blueprints from maps
|
||||||
for (const FAssetData& MapAsset : UMCPAssetFinder::GetAssets(UWorld::StaticClass()))
|
for (const FAssetData& MapAsset : AllWorlds.AllData())
|
||||||
{
|
{
|
||||||
if (Results.Num() >= EffectiveMaxResults) break;
|
if (Results.Num() >= EffectiveMaxResults) break;
|
||||||
|
|
||||||
@@ -722,7 +730,6 @@ public:
|
|||||||
SearchOneBlueprint(MapName, AssetPath, LevelBP, true);
|
SearchOneBlueprint(MapName, AssetPath, LevelBP, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetStringField(TEXT("typeName"), DecodedTypeName);
|
|
||||||
Result->SetNumberField(TEXT("resultCount"), Results.Num());
|
Result->SetNumberField(TEXT("resultCount"), Results.Num());
|
||||||
Result->SetArrayField(TEXT("results"), Results);
|
Result->SetArrayField(TEXT("results"), Results);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UAnimationStateMachineGraph* SMGraph = UMCPAssetFinder::LoadAnimStateMachineGraph(Blueprint, Graph, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!SMGraph) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UAnimBlueprint* AnimBP = SMGraph->GetTypedOuter<UAnimBlueprint>();
|
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
|
||||||
|
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
// Check for duplicate state name
|
// Check for duplicate state name
|
||||||
if (MCPUtils::FindStateByName(SMGraph, StateName, nullptr))
|
if (MCPUtils::FindStateByName(SMGraph, StateName, nullptr))
|
||||||
@@ -88,8 +90,8 @@ public:
|
|||||||
if (!AnimationAsset.IsEmpty() && NewState->GetBoundGraph())
|
if (!AnimationAsset.IsEmpty() && NewState->GetBoundGraph())
|
||||||
{
|
{
|
||||||
// Try to find the animation asset and create a sequence player in the state's inner graph
|
// Try to find the animation asset and create a sequence player in the state's inner graph
|
||||||
FAssetData* FoundAnimAsset = UMCPAssetFinder::FindAsset(UAnimSequence::StaticClass(), AnimationAsset);
|
MCPAssets<UAnimSequence> AnimAssets;
|
||||||
UAnimSequence* AnimSeq = FoundAnimAsset ? Cast<UAnimSequence>(FoundAnimAsset->GetAsset()) : nullptr;
|
UAnimSequence* AnimSeq = AnimAssets.Exact(AnimationAsset).ENone().ETwo().Load() ? AnimAssets.Object() : nullptr;
|
||||||
|
|
||||||
if (AnimSeq)
|
if (AnimSeq)
|
||||||
{
|
{
|
||||||
@@ -108,9 +110,6 @@ public:
|
|||||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("stateName"), StateName);
|
|
||||||
Result->SetStringField(TEXT("graph"), Graph);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), NewState->NodeGuid.ToString());
|
Result->SetStringField(TEXT("nodeId"), NewState->NodeGuid.ToString());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
@@ -142,9 +141,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UAnimationStateMachineGraph* SMGraph = UMCPAssetFinder::LoadAnimStateMachineGraph(Blueprint, Graph, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!SMGraph) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UAnimBlueprint* AnimBP = SMGraph->GetTypedOuter<UAnimBlueprint>();
|
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
|
||||||
|
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName, Result);
|
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName, Result);
|
||||||
if (!StateNode) return;
|
if (!StateNode) return;
|
||||||
@@ -177,8 +178,6 @@ public:
|
|||||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("removedState"), StateName);
|
|
||||||
Result->SetNumberField(TEXT("removedTransitions"), RemovedTransitions);
|
Result->SetNumberField(TEXT("removedTransitions"), RemovedTransitions);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
@@ -222,9 +221,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UAnimationStateMachineGraph* SMGraph = UMCPAssetFinder::LoadAnimStateMachineGraph(Blueprint, Graph, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!SMGraph) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UAnimBlueprint* AnimBP = SMGraph->GetTypedOuter<UAnimBlueprint>();
|
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
|
||||||
|
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
UAnimStateNode* FromStateNode = MCPUtils::FindStateByName(SMGraph, FromState, Result);
|
UAnimStateNode* FromStateNode = MCPUtils::FindStateByName(SMGraph, FromState, Result);
|
||||||
if (!FromStateNode) return;
|
if (!FromStateNode) return;
|
||||||
@@ -266,13 +267,7 @@ public:
|
|||||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("fromState"), FromState);
|
|
||||||
Result->SetStringField(TEXT("toState"), ToState);
|
|
||||||
Result->SetStringField(TEXT("nodeId"), TransNode->NodeGuid.ToString());
|
Result->SetStringField(TEXT("nodeId"), TransNode->NodeGuid.ToString());
|
||||||
Result->SetNumberField(TEXT("crossfadeDuration"), TransNode->CrossfadeDuration);
|
|
||||||
Result->SetNumberField(TEXT("priorityOrder"), TransNode->PriorityOrder);
|
|
||||||
Result->SetBoolField(TEXT("bBidirectional"), TransNode->Bidirectional);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -321,9 +316,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UAnimationStateMachineGraph* SMGraph = UMCPAssetFinder::LoadAnimStateMachineGraph(Blueprint, Graph, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!SMGraph) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UAnimBlueprint* AnimBP = SMGraph->GetTypedOuter<UAnimBlueprint>();
|
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
|
||||||
|
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
UAnimStateTransitionNode* TransNode = MCPUtils::FindTransition(SMGraph, FromState, ToState);
|
UAnimStateTransitionNode* TransNode = MCPUtils::FindTransition(SMGraph, FromState, ToState);
|
||||||
if (!TransNode)
|
if (!TransNode)
|
||||||
@@ -371,15 +368,7 @@ public:
|
|||||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("fromState"), FromState);
|
|
||||||
Result->SetStringField(TEXT("toState"), ToState);
|
|
||||||
Result->SetNumberField(TEXT("propertiesChanged"), ChangedCount);
|
Result->SetNumberField(TEXT("propertiesChanged"), ChangedCount);
|
||||||
Result->SetNumberField(TEXT("crossfadeDuration"), TransNode->CrossfadeDuration);
|
|
||||||
Result->SetNumberField(TEXT("blendMode"), (int32)TransNode->BlendMode);
|
|
||||||
Result->SetNumberField(TEXT("priorityOrder"), TransNode->PriorityOrder);
|
|
||||||
Result->SetNumberField(TEXT("logicType"), (int32)TransNode->LogicType.GetValue());
|
|
||||||
Result->SetBoolField(TEXT("bBidirectional"), TransNode->Bidirectional);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -413,9 +402,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UAnimationStateMachineGraph* SMGraph = UMCPAssetFinder::LoadAnimStateMachineGraph(Blueprint, Graph, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!SMGraph) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UAnimBlueprint* AnimBP = SMGraph->GetTypedOuter<UAnimBlueprint>();
|
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
|
||||||
|
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName, Result);
|
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName, Result);
|
||||||
if (!StateNode) return;
|
if (!StateNode) return;
|
||||||
@@ -427,8 +418,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the animation asset
|
// Find the animation asset
|
||||||
UAnimSequence* AnimSeq = UMCPAssetFinder::LoadAsset<UAnimSequence>(AnimationAsset, Result);
|
MCPAssets<UAnimSequence> AnimAssets;
|
||||||
if (!AnimSeq) return;
|
if (!AnimAssets.Exact(AnimationAsset).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UAnimSequence* AnimSeq = AnimAssets.Object();
|
||||||
|
|
||||||
// Find existing SequencePlayer or create one
|
// Find existing SequencePlayer or create one
|
||||||
UAnimGraphNode_SequencePlayer* SeqNode = nullptr;
|
UAnimGraphNode_SequencePlayer* SeqNode = nullptr;
|
||||||
@@ -457,9 +449,6 @@ public:
|
|||||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("stateName"), StateName);
|
|
||||||
Result->SetStringField(TEXT("animationAsset"), AnimSeq->GetName());
|
|
||||||
Result->SetBoolField(TEXT("createdNewNode"), bCreatedNew);
|
Result->SetBoolField(TEXT("createdNewNode"), bCreatedNew);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
@@ -501,9 +490,11 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
UAnimationStateMachineGraph* SMGraph = UMCPAssetFinder::LoadAnimStateMachineGraph(Blueprint, Graph, Result);
|
MCPAssets<UAnimBlueprint> Assets;
|
||||||
if (!SMGraph) return;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UAnimBlueprint* AnimBP = SMGraph->GetTypedOuter<UAnimBlueprint>();
|
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(Assets.Object(), Graph);
|
||||||
|
if (!SMGraph) { MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("State machine graph '%s' not found in '%s'"), *Graph, *Blueprint)); return; }
|
||||||
|
UAnimBlueprint* AnimBP = Assets.Object();
|
||||||
|
|
||||||
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName, Result);
|
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName, Result);
|
||||||
if (!StateNode) return;
|
if (!StateNode) return;
|
||||||
@@ -515,8 +506,9 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the blend space asset
|
// Find the blend space asset
|
||||||
UBlendSpace* BlendSpaceAsset = UMCPAssetFinder::LoadAsset<UBlendSpace>(BlendSpace, Result);
|
MCPAssets<UBlendSpace> BlendSpaceAssets;
|
||||||
if (!BlendSpaceAsset) return;
|
if (!BlendSpaceAssets.Exact(BlendSpace).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UBlendSpace* BlendSpaceAsset = BlendSpaceAssets.Object();
|
||||||
|
|
||||||
// Find existing BlendSpacePlayer or create one
|
// Find existing BlendSpacePlayer or create one
|
||||||
UAnimGraphNode_BlendSpacePlayer* BSNode = nullptr;
|
UAnimGraphNode_BlendSpacePlayer* BSNode = nullptr;
|
||||||
@@ -665,9 +657,6 @@ public:
|
|||||||
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
FKismetEditorUtilities::CompileBlueprint(AnimBP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("stateName"), StateName);
|
|
||||||
Result->SetStringField(TEXT("blendSpace"), BlendSpaceAsset->GetName());
|
|
||||||
Result->SetStringField(TEXT("nodeId"), BSNode->NodeGuid.ToString());
|
Result->SetStringField(TEXT("nodeId"), BSNode->NodeGuid.ToString());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,8 +123,6 @@ public:
|
|||||||
// Save
|
// Save
|
||||||
bool bSaved = MCPUtils::SaveGenericPackage(NewStruct);
|
bool bSaved = MCPUtils::SaveGenericPackage(NewStruct);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
||||||
Result->SetStringField(TEXT("assetName"), AssetName);
|
Result->SetStringField(TEXT("assetName"), AssetName);
|
||||||
Result->SetNumberField(TEXT("propertiesAdded"), PropsAdded);
|
Result->SetNumberField(TEXT("propertiesAdded"), PropsAdded);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -203,8 +201,6 @@ public:
|
|||||||
// Save
|
// Save
|
||||||
bool bSaved = MCPUtils::SaveGenericPackage(NewEnum);
|
bool bSaved = MCPUtils::SaveGenericPackage(NewEnum);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
||||||
Result->SetStringField(TEXT("assetName"), AssetName);
|
Result->SetStringField(TEXT("assetName"), AssetName);
|
||||||
Result->SetNumberField(TEXT("valueCount"), EnumValues.Num());
|
Result->SetNumberField(TEXT("valueCount"), EnumValues.Num());
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
@@ -238,8 +234,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Find the struct
|
// Find the struct
|
||||||
UUserDefinedStruct* Struct = UMCPAssetFinder::LoadAsset<UUserDefinedStruct>(AssetPath, Result);
|
MCPAssets<UUserDefinedStruct> Assets;
|
||||||
if (!Struct) return;
|
if (!Assets.Exact(AssetPath).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UUserDefinedStruct* Struct = Assets.Object();
|
||||||
|
|
||||||
// Resolve type
|
// Resolve type
|
||||||
FEdGraphPinType PinType;
|
FEdGraphPinType PinType;
|
||||||
@@ -272,10 +269,6 @@ public:
|
|||||||
// Save
|
// Save
|
||||||
bool bSaved = MCPUtils::SaveGenericPackage(Struct);
|
bool bSaved = MCPUtils::SaveGenericPackage(Struct);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
||||||
Result->SetStringField(TEXT("propertyName"), Name);
|
|
||||||
Result->SetStringField(TEXT("propertyType"), Type);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -304,8 +297,9 @@ public:
|
|||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Find the struct
|
// Find the struct
|
||||||
UUserDefinedStruct* Struct = UMCPAssetFinder::LoadAsset<UUserDefinedStruct>(AssetPath, Result);
|
MCPAssets<UUserDefinedStruct> Assets;
|
||||||
if (!Struct) return;
|
if (!Assets.Exact(AssetPath).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
UUserDefinedStruct* Struct = Assets.Object();
|
||||||
|
|
||||||
// Find the property GUID by name
|
// Find the property GUID by name
|
||||||
FGuid TargetGuid;
|
FGuid TargetGuid;
|
||||||
@@ -342,9 +336,6 @@ public:
|
|||||||
// Save
|
// Save
|
||||||
bool bSaved = MCPUtils::SaveGenericPackage(Struct);
|
bool bSaved = MCPUtils::SaveGenericPackage(Struct);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("assetPath"), AssetPath);
|
|
||||||
Result->SetStringField(TEXT("removedProperty"), Name);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -136,21 +136,21 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
TArray<FAssetData*> MatchingAssets;
|
MCPAssets<UBlueprint> Finder;
|
||||||
|
Finder.Scan<UBlueprint>().Scan<UWorld>();
|
||||||
if (!Blueprint.IsEmpty())
|
if (!Blueprint.IsEmpty())
|
||||||
{
|
{
|
||||||
FAssetData* Asset = UMCPAssetFinder::FindAsset(UMCPAssetFinder::BlueprintsAndMaps, Blueprint);
|
if (!Finder.Exact(Blueprint).ETwo().Info() || Finder.AllData().IsEmpty())
|
||||||
if (!Asset)
|
|
||||||
{
|
{
|
||||||
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Blueprint '%s' not found."), *Blueprint));
|
return MCPUtils::MakeErrorJson(Result, FString::Printf(TEXT("Blueprint '%s' not found."), *Blueprint));
|
||||||
}
|
}
|
||||||
MatchingAssets.Add(Asset);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MatchingAssets = UMCPAssetFinder::SearchAssets(UMCPAssetFinder::BlueprintsAndMaps, Query);
|
Finder.Substring(Query).Info();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TArray<FAssetData>& MatchingAssets = Finder.AllData();
|
||||||
int32 TotalMatching = MatchingAssets.Num();
|
int32 TotalMatching = MatchingAssets.Num();
|
||||||
|
|
||||||
// countOnly: return count without compiling anything
|
// countOnly: return count without compiling anything
|
||||||
@@ -179,17 +179,18 @@ public:
|
|||||||
|
|
||||||
for (int32 Idx = StartIdx; Idx < EndIdx; Idx++)
|
for (int32 Idx = StartIdx; Idx < EndIdx; Idx++)
|
||||||
{
|
{
|
||||||
FAssetData* Asset = MatchingAssets[Idx];
|
const FAssetData& Asset = MatchingAssets[Idx];
|
||||||
FString AssetName = Asset->AssetName.ToString();
|
FString AssetName = Asset.AssetName.ToString();
|
||||||
FString PackagePath = Asset->PackageName.ToString();
|
FString PackagePath = Asset.PackageName.ToString();
|
||||||
|
|
||||||
// Load the Blueprint (handles both regular and level blueprints)
|
// Load the Blueprint (handles both regular and level blueprints)
|
||||||
FString LoadError;
|
MCPAssets<UBlueprint> Loader;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(PackagePath, LoadError);
|
Loader.Scan<UBlueprint>().Scan<UWorld>();
|
||||||
if (!BP)
|
if (!Loader.Exact(PackagePath).ENone().ETwo().Load())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
UBlueprint* BP = Loader.Object();
|
||||||
|
|
||||||
TotalChecked++;
|
TotalChecked++;
|
||||||
|
|
||||||
|
|||||||
@@ -45,13 +45,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify variable exists
|
// Verify variable exists
|
||||||
bool bVarFound = false;
|
bool bVarFound = false;
|
||||||
@@ -170,9 +166,6 @@ public:
|
|||||||
if (DryRun)
|
if (DryRun)
|
||||||
{
|
{
|
||||||
Result->SetBoolField(TEXT("dryRun"), true);
|
Result->SetBoolField(TEXT("dryRun"), true);
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("variable"), Variable);
|
|
||||||
Result->SetStringField(TEXT("newType"), NewType);
|
|
||||||
Result->SetStringField(TEXT("typeCategory"), ResolvedTypeCategory);
|
Result->SetStringField(TEXT("typeCategory"), ResolvedTypeCategory);
|
||||||
Result->SetNumberField(TEXT("affectedNodeCount"), AffectedNodes.Num());
|
Result->SetNumberField(TEXT("affectedNodeCount"), AffectedNodes.Num());
|
||||||
Result->SetArrayField(TEXT("affectedNodes"), AffectedNodes);
|
Result->SetArrayField(TEXT("affectedNodes"), AffectedNodes);
|
||||||
@@ -209,10 +202,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("variable"), Variable);
|
|
||||||
Result->SetStringField(TEXT("newType"), NewType);
|
|
||||||
Result->SetStringField(TEXT("typeCategory"), ResolvedTypeCategory);
|
Result->SetStringField(TEXT("typeCategory"), ResolvedTypeCategory);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
Result->SetObjectField(TEXT("updatedVariable"), UpdatedVar);
|
Result->SetObjectField(TEXT("updatedVariable"), UpdatedVar);
|
||||||
@@ -255,13 +244,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for duplicate variable name
|
// Check for duplicate variable name
|
||||||
FName VarFName(*VariableName);
|
FName VarFName(*VariableName);
|
||||||
@@ -308,15 +293,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added variable '%s' to '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Added variable '%s' to '%s' (saved: %s)"),
|
||||||
*VariableName, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
*VariableName, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("variableName"), VariableName);
|
|
||||||
Result->SetStringField(TEXT("variableType"), VariableType);
|
|
||||||
if (!Category.IsEmpty())
|
|
||||||
{
|
|
||||||
Result->SetStringField(TEXT("category"), Category);
|
|
||||||
}
|
|
||||||
Result->SetBoolField(TEXT("isArray"), IsArray);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -344,13 +320,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find variable by name (case-insensitive)
|
// Find variable by name (case-insensitive)
|
||||||
FName VarFName(*VariableName);
|
FName VarFName(*VariableName);
|
||||||
@@ -392,9 +364,6 @@ public:
|
|||||||
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed variable '%s' from '%s' (saved: %s)"),
|
UE_LOG(LogTemp, Display, TEXT("BlueprintMCP: Removed variable '%s' from '%s' (saved: %s)"),
|
||||||
*VariableName, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
*VariableName, *Blueprint, bSaved ? TEXT("true") : TEXT("false"));
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("variableName"), VariableName);
|
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -441,13 +410,9 @@ public:
|
|||||||
|
|
||||||
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
virtual void Handle(const FJsonObject* Json, FJsonObject* Result) override
|
||||||
{
|
{
|
||||||
// Load Blueprint
|
MCPAssets<UBlueprint> Assets;
|
||||||
FString LoadError;
|
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
UBlueprint* BP = UMCPAssetFinder::LoadBlueprintOrLevelBlueprint(Blueprint, LoadError);
|
UBlueprint* BP = Assets.Object();
|
||||||
if (!BP)
|
|
||||||
{
|
|
||||||
return MCPUtils::MakeErrorJson(Result, LoadError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the variable
|
// Find the variable
|
||||||
FName VarFName(*Variable);
|
FName VarFName(*Variable);
|
||||||
@@ -616,9 +581,6 @@ public:
|
|||||||
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
|
||||||
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
|
||||||
|
|
||||||
Result->SetBoolField(TEXT("success"), true);
|
|
||||||
Result->SetStringField(TEXT("blueprint"), Blueprint);
|
|
||||||
Result->SetStringField(TEXT("variable"), Variable);
|
|
||||||
Result->SetArrayField(TEXT("changes"), Changes);
|
Result->SetArrayField(TEXT("changes"), Changes);
|
||||||
Result->SetBoolField(TEXT("saved"), bSaved);
|
Result->SetBoolField(TEXT("saved"), bSaved);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,16 @@
|
|||||||
#include "StructUtils/UserDefinedStruct.h"
|
#include "StructUtils/UserDefinedStruct.h"
|
||||||
#include "Engine/UserDefinedEnum.h"
|
#include "Engine/UserDefinedEnum.h"
|
||||||
#include "MCPUtils.h"
|
#include "MCPUtils.h"
|
||||||
|
#include "Engine/Blueprint.h"
|
||||||
|
#include "Engine/LevelScriptBlueprint.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
#include "MCPAssetFinder.generated.h"
|
#include "MCPAssetFinder.generated.h"
|
||||||
|
|
||||||
class UBlueprint;
|
|
||||||
class UMaterial;
|
class UMaterial;
|
||||||
class UMaterialInstanceConstant;
|
class UMaterialInstanceConstant;
|
||||||
class UMaterialFunction;
|
class UMaterialFunction;
|
||||||
class UAnimationStateMachineGraph;
|
class UAnimationStateMachineGraph;
|
||||||
class IAssetRegistry;
|
class IAssetRegistry;
|
||||||
|
struct FARFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Engine subsystem that caches asset registry data for the BlueprintMCP server.
|
* Engine subsystem that caches asset registry data for the BlueprintMCP server.
|
||||||
@@ -104,3 +106,79 @@ private:
|
|||||||
// Empty array returned when subsystem is unavailable
|
// Empty array returned when subsystem is unavailable
|
||||||
static const TArray<FAssetData> EmptyAssetArray;
|
static const TArray<FAssetData> EmptyAssetArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// MCPAssetsBase — non-template base for MCPAssets<T>
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
class MCPAssetsBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MCPAssetsBase(UClass* InTargetClass);
|
||||||
|
MCPAssetsBase& Scan(UClass* Class) { Classes.Add(Class); return *this; }
|
||||||
|
template<class T> MCPAssetsBase& Scan() { return Scan(T::StaticClass()); }
|
||||||
|
MCPAssetsBase& Exact(const FString& InName);
|
||||||
|
MCPAssetsBase& Substring(const FString& InFilter);
|
||||||
|
MCPAssetsBase& Limit(int32 Count) { MaxResults = Count; return *this; }
|
||||||
|
MCPAssetsBase& NoDerived();
|
||||||
|
MCPAssetsBase& AllContent();
|
||||||
|
MCPAssetsBase& Errors(MCPErrorCallback InCB);
|
||||||
|
MCPAssetsBase& EAny() { bErrorIfAny = true; return *this; }
|
||||||
|
MCPAssetsBase& ENone() { bErrorIfNone = true; return *this; }
|
||||||
|
MCPAssetsBase& ETwo() { bErrorIfTwo = true; return *this; }
|
||||||
|
|
||||||
|
bool Load();
|
||||||
|
bool Info();
|
||||||
|
|
||||||
|
const TArray<FAssetData>& AllData() const { return AssetResults; }
|
||||||
|
const FAssetData& OneData() const { return AssetResults[0]; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool Execute(bool bLoad);
|
||||||
|
void ConfigureFilterClassPaths(FARFilter &Filter);
|
||||||
|
bool AssetMatches(const FAssetData &Data);
|
||||||
|
UObject *TryLoadAsset(const FAssetData &Asset);
|
||||||
|
void SetError(const FString &Msg);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UClass* TargetClass;
|
||||||
|
TArray<UClass*, TInlineAllocator<4>> Classes;
|
||||||
|
TArray<FAssetData> AssetResults;
|
||||||
|
TArray<UObject*> UObjectResults;
|
||||||
|
FString MatchName;
|
||||||
|
bool bExactMatch = false;
|
||||||
|
bool bPatternHasSlash = false;
|
||||||
|
bool bNoDerived = false;
|
||||||
|
bool bAllContent = false;
|
||||||
|
bool bErrorIfAny = false;
|
||||||
|
bool bErrorIfNone = false;
|
||||||
|
bool bErrorIfTwo = false;
|
||||||
|
int32 MaxResults = 50;
|
||||||
|
MCPErrorCallback ErrorCB = MCPErrorCallback(nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// MCPAssets<T> — builder-pattern asset finder
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// MCPAssets<UBlueprint> Assets;
|
||||||
|
// if (!Assets.Exact(Name).Errors(Result).ENone().ETwo().Load()) return;
|
||||||
|
// UBlueprint* BP = Assets.Object();
|
||||||
|
//
|
||||||
|
// MCPAssets<UMaterial> Materials;
|
||||||
|
// if (!Materials.Substring(Filter).Limit(100).Load()) return;
|
||||||
|
// for (UMaterial* Mat : Materials.Objects()) { ... }
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class MCPAssets : public MCPAssetsBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MCPAssets() : MCPAssetsBase(T::StaticClass()) {}
|
||||||
|
|
||||||
|
TArrayView<T* const> Objects() const
|
||||||
|
{
|
||||||
|
return TArrayView<T* const>(reinterpret_cast<T* const*>(UObjectResults.GetData()), UObjectResults.Num());
|
||||||
|
}
|
||||||
|
T* Object() const { return static_cast<T*>(UObjectResults[0]); }
|
||||||
|
};
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ struct MCPErrorCallback
|
|||||||
{
|
{
|
||||||
TFunction<void(const FString&)> Func;
|
TFunction<void(const FString&)> Func;
|
||||||
|
|
||||||
|
|
||||||
MCPErrorCallback(std::nullptr_t);
|
MCPErrorCallback(std::nullptr_t);
|
||||||
MCPErrorCallback(FString& OutError);
|
MCPErrorCallback(FString& OutError);
|
||||||
MCPErrorCallback(FJsonObject* Result);
|
MCPErrorCallback(FJsonObject* Result);
|
||||||
|
|||||||
Reference in New Issue
Block a user