Remove stringbuilder parameter for handlers

This commit is contained in:
2026-03-13 23:41:59 -04:00
parent 7cfe73eca8
commit 2ffc493e91
76 changed files with 539 additions and 467 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -37,7 +38,7 @@ public:
return TEXT("Create a new Animation Blueprint asset with a specified skeleton.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -94,14 +95,14 @@ public:
FKismetEditorUtilities::CompileBlueprint(NewAnimBP);
bool bSaved = MCPUtils::SaveBlueprintPackage(NewAnimBP);
Result.Appendf(TEXT("Created: %s\n"), *AssetPath);
Result.Appendf(TEXT("ParentClass: %s\n"), *MCPUtils::FormatName(ParentClassObj));
Result.Appendf(TEXT("Saved: %s\n"), bSaved ? TEXT("true") : TEXT("false"));
UMCPServer::Printf(TEXT("Created: %s\n"), *AssetPath);
UMCPServer::Printf(TEXT("ParentClass: %s\n"), *MCPUtils::FormatName(ParentClassObj));
UMCPServer::Printf(TEXT("Saved: %s\n"), bSaved ? TEXT("true") : TEXT("false"));
TArray<UEdGraph*> Graphs = MCPUtils::AllGraphs(NewAnimBP);
for (UEdGraph* Graph : Graphs)
{
Result.Appendf(TEXT("Graph: %s\n"), *MCPUtils::FormatName(Graph));
UMCPServer::Printf(TEXT("Graph: %s\n"), *MCPUtils::FormatName(Graph));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -27,7 +28,7 @@ public:
return TEXT("List all animation slot names used in an Animation Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UAnimBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -52,12 +53,12 @@ public:
for (const FString& Slot : SlotNames)
{
Result.Appendf(TEXT("%s\n"), *Slot);
UMCPServer::Printf(TEXT("%s\n"), *Slot);
}
if (SlotNames.Num() == 0)
{
Result.Append(TEXT("No animation slot names found.\n"));
UMCPServer::Print(TEXT("No animation slot names found.\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -27,7 +28,7 @@ public:
return TEXT("List all sync group names used in an Animation Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UAnimBlueprint* AnimBP = F.Walk(Path).Cast<UAnimBlueprint>();
@@ -52,13 +53,13 @@ public:
if (SyncGroupNames.Num() == 0)
{
Result.Append(TEXT("No sync groups found.\n"));
UMCPServer::Print(TEXT("No sync groups found.\n"));
return;
}
for (const FString& Group : SyncGroupNames)
{
Result.Appendf(TEXT("%s\n"), *Group);
UMCPServer::Printf(TEXT("%s\n"), *Group);
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPFetcher.h"
@@ -65,7 +66,7 @@ public:
"Replaces all existing samples.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load the blend space
MCPAssets<UBlendSpace> Assets;
@@ -128,10 +129,10 @@ public:
// Save
bool bSaved = MCPUtils::SaveGenericPackage(BS);
Result.Appendf(TEXT("Set %d samples on %s\n"), SamplesSet, *MCPUtils::FormatName(BS));
UMCPServer::Printf(TEXT("Set %d samples on %s\n"), SamplesSet, *MCPUtils::FormatName(BS));
if (!bSaved)
{
Result.Append(TEXT("WARNING: package save failed\n"));
UMCPServer::Print(TEXT("WARNING: package save failed\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "Misc/Paths.h"
@@ -27,14 +28,14 @@ public:
return TEXT("Copy an asset's .uasset file to a .uasset.bak backup.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
FString Filename = FPaths::ConvertRelativePathToFull(
FPackageName::LongPackageNameToFilename(AssetPath, FPackageName::GetAssetPackageExtension()));
if (!IFileManager::Get().FileExists(*Filename))
{
Result.Appendf(TEXT("ERROR: Asset file not found: %s\n"), *Filename);
UMCPServer::Printf(TEXT("ERROR: Asset file not found: %s\n"), *Filename);
return;
}
@@ -42,10 +43,10 @@ public:
uint32 CopyResult = IFileManager::Get().Copy(*BackupFilename, *Filename, true);
if (CopyResult != COPY_OK)
{
Result.Appendf(TEXT("ERROR: Failed to copy %s to %s\n"), *Filename, *BackupFilename);
UMCPServer::Printf(TEXT("ERROR: Failed to copy %s to %s\n"), *Filename, *BackupFilename);
return;
}
Result.Appendf(TEXT("Backed up to %s\n"), *BackupFilename);
UMCPServer::Printf(TEXT("Backed up to %s\n"), *BackupFilename);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -34,7 +35,7 @@ public:
"Use force=true to skip the reference check.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Verify the asset file exists on disk
FString PackageFilename = FPackageName::LongPackageNameToFilename(
@@ -43,7 +44,7 @@ public:
if (!IFileManager::Get().FileExists(*PackageFilename))
{
Result.Appendf(TEXT("ERROR: Asset file not found on disk: %s\n"), *PackageFilename);
UMCPServer::Printf(TEXT("ERROR: Asset file not found on disk: %s\n"), *PackageFilename);
return;
}
@@ -59,22 +60,22 @@ public:
if (Referencers.Num() > 0 && !Force)
{
Result.Appendf(TEXT("ERROR: Asset is still referenced by %d package(s):\n"), Referencers.Num());
UMCPServer::Printf(TEXT("ERROR: Asset is still referenced by %d package(s):\n"), Referencers.Num());
for (const FName& Ref : Referencers)
{
FString RefStr = Ref.ToString();
UPackage* RefPackage = FindPackage(nullptr, *RefStr);
Result.Appendf(TEXT(" %s%s\n"), *RefStr,
UMCPServer::Printf(TEXT(" %s%s\n"), *RefStr,
RefPackage ? TEXT(" (loaded)") : TEXT(" (on-disk only)"));
}
Result.Append(TEXT("Use force=true to skip the reference check.\n"));
UMCPServer::Print(TEXT("Use force=true to skip the reference check.\n"));
return;
}
// Force delete: unload the package from memory first
if (Force && Referencers.Num() > 0)
{
Result.Appendf(TEXT("WARNING: Force-deleting despite %d referencer(s).\n"), Referencers.Num());
UMCPServer::Printf(TEXT("WARNING: Force-deleting despite %d referencer(s).\n"), Referencers.Num());
}
if (Force)
@@ -110,7 +111,7 @@ public:
if (!bDeleted)
{
Result.Appendf(TEXT("ERROR: Failed to delete file from disk: %s\n"), *PackageFilename);
UMCPServer::Printf(TEXT("ERROR: Failed to delete file from disk: %s\n"), *PackageFilename);
return;
}
@@ -123,6 +124,6 @@ public:
Registry.ScanPathsSynchronous({PackageDir}, true);
}
Result.Appendf(TEXT("Deleted %s\n"), *AssetPath);
UMCPServer::Printf(TEXT("Deleted %s\n"), *AssetPath);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "AssetRegistry/AssetData.h"
@@ -26,7 +27,7 @@ public:
return TEXT("Find all assets that reference a given asset.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
IAssetRegistry& Registry = *IAssetRegistry::Get();
@@ -34,7 +35,7 @@ public:
FAssetData AssetData = Registry.GetAssetByObjectPath(FSoftObjectPath(AssetPath));
if (!AssetData.IsValid())
{
Result.Appendf(TEXT("ERROR: Asset not found: %s\n"), *AssetPath);
UMCPServer::Printf(TEXT("ERROR: Asset not found: %s\n"), *AssetPath);
return;
}
@@ -43,7 +44,7 @@ public:
if (Referencers.Num() == 0)
{
Result.Append(TEXT("No referencers found.\n"));
UMCPServer::Print(TEXT("No referencers found.\n"));
return;
}
@@ -55,13 +56,13 @@ public:
Registry.GetAssetsByPackageName(Ref, RefAssets);
if (RefAssets.Num() > 0)
{
Result.Appendf(TEXT("%s %s\n"),
UMCPServer::Printf(TEXT("%s %s\n"),
*MCPUtils::FormatName(RefAssets[0].GetClass()),
*RefStr);
}
else
{
Result.Appendf(TEXT("Unknown %s\n"), *RefStr);
UMCPServer::Printf(TEXT("Unknown %s\n"), *RefStr);
}
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -30,7 +31,7 @@ public:
return TEXT("Rename or move an asset with reference fixup.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load the asset
MCPAssets<UObject> Assets;
@@ -47,7 +48,7 @@ public:
NewAssetName = NewPath;
if (NewPackagePath.IsEmpty())
{
Result.Appendf(TEXT("ERROR: Cannot determine directory from AssetPath '%s'\n"), *AssetPath);
UMCPServer::Printf(TEXT("ERROR: Cannot determine directory from AssetPath '%s'\n"), *AssetPath);
return;
}
}
@@ -61,10 +62,10 @@ public:
if (!AssetTools.RenameAssets(RenameData))
{
Result.Append(TEXT("ERROR: Rename failed. The target path may be invalid or a conflicting asset may exist.\n"));
UMCPServer::Print(TEXT("ERROR: Rename failed. The target path may be invalid or a conflicting asset may exist.\n"));
return;
}
Result.Appendf(TEXT("Renamed to %s/%s\n"), *NewPackagePath, *NewAssetName);
UMCPServer::Printf(TEXT("Renamed to %s/%s\n"), *NewPackagePath, *NewAssetName);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "Misc/PackageName.h"
@@ -28,7 +29,7 @@ public:
return TEXT("Restore a .uasset file from its .uasset.bak backup, reloading it in the editor.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
FString Filename = FPaths::ConvertRelativePathToFull(
FPackageName::LongPackageNameToFilename(AssetPath, FPackageName::GetAssetPackageExtension()));
@@ -36,7 +37,7 @@ public:
if (!IFileManager::Get().FileExists(*BackupFilename))
{
Result.Appendf(TEXT("ERROR: Backup file not found: %s\n"), *BackupFilename);
UMCPServer::Printf(TEXT("ERROR: Backup file not found: %s\n"), *BackupFilename);
return;
}
@@ -51,7 +52,7 @@ public:
uint32 CopyResult = IFileManager::Get().Copy(*Filename, *BackupFilename, true);
if (CopyResult != COPY_OK)
{
Result.Appendf(TEXT("ERROR: Failed to copy backup over %s\n"), *AssetPath);
UMCPServer::Printf(TEXT("ERROR: Failed to copy backup over %s\n"), *AssetPath);
return;
}
@@ -63,12 +64,12 @@ public:
UEditorLoadingAndSavingUtils::ReloadPackages({Package}, bReloaded, ErrorMessage, EReloadPackagesInteractionMode::AssumePositive);
if (!bReloaded)
{
Result.Appendf(TEXT("WARNING: Restored %s but reload failed: %s\n"),
UMCPServer::Printf(TEXT("WARNING: Restored %s but reload failed: %s\n"),
*AssetPath, *ErrorMessage.ToString());
return;
}
}
Result.Appendf(TEXT("Restored %s from backup\n"), *AssetPath);
UMCPServer::Printf(TEXT("Restored %s from backup\n"), *AssetPath);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -31,11 +32,11 @@ public:
return TEXT("Search for assets by name and/or type. At least one of Query or Type must be specified.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
if (Query.IsEmpty() && Type.IsEmpty())
{
Result.Append(TEXT("ERROR: At least one of Query or Type must be specified\n"));
UMCPServer::Print(TEXT("ERROR: At least one of Query or Type must be specified\n"));
return;
}
@@ -47,7 +48,7 @@ public:
UClass* TypeClass = MCPUtils::FindClassByName(Type);
if (!TypeClass)
{
Result.Appendf(TEXT("ERROR: Unknown asset type '%s'\n"), *Type);
UMCPServer::Printf(TEXT("ERROR: Unknown asset type '%s'\n"), *Type);
return;
}
Assets.NoScans().Scan(TypeClass);
@@ -63,18 +64,18 @@ public:
const TArray<FAssetData>& AllData = Assets.AllData();
for (const FAssetData& Data : AllData)
{
Result.Appendf(TEXT("%s %s\n"),
UMCPServer::Printf(TEXT("%s %s\n"),
*MCPUtils::FormatName(Data.GetClass()),
*Data.PackageName.ToString());
}
if (AllData.Num() == 0)
{
Result.Append(TEXT("No assets found.\n"));
UMCPServer::Print(TEXT("No assets found.\n"));
}
else if (AllData.Num() >= Limit)
{
Result.Appendf(TEXT("WARNING: You reached the limit of %d, to raise it, specify the Limit parameter.\n"), Limit);
UMCPServer::Printf(TEXT("WARNING: You reached the limit of %d, to raise it, specify the Limit parameter.\n"), Limit);
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
return TEXT("Create a new 2D Blend Space asset with a specified skeleton.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -46,7 +47,7 @@ public:
UBlendSpace* NewBS = NewObject<UBlendSpace>(Maker.Package(), FName(*Maker.Name()), RF_Public | RF_Standalone);
if (!NewBS)
{
Result.Append(TEXT("ERROR: Failed to create Blend Space object\n"));
UMCPServer::Print(TEXT("ERROR: Failed to create Blend Space object\n"));
return;
}
@@ -56,9 +57,9 @@ public:
NewBS->MarkPackageDirty();
bool bSaved = MCPUtils::SaveGenericPackage(NewBS);
Result.Appendf(TEXT("Created %s\n"), *NewBS->GetPathName());
Result.Appendf(TEXT("Skeleton: %s\n"), *SkeletonObj->GetPathName());
UMCPServer::Printf(TEXT("Created %s\n"), *NewBS->GetPathName());
UMCPServer::Printf(TEXT("Skeleton: %s\n"), *SkeletonObj->GetPathName());
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -37,11 +38,11 @@ public:
return TEXT("Create a new function, macro, or custom event graph in a Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
if (GraphType != TEXT("function") && GraphType != TEXT("macro") && GraphType != TEXT("customEvent"))
{
Result.Appendf(TEXT("ERROR: Invalid GraphType '%s'. Valid values: function, macro, customEvent\n"), *GraphType);
UMCPServer::Printf(TEXT("ERROR: Invalid GraphType '%s'. Valid values: function, macro, customEvent\n"), *GraphType);
return;
}
@@ -52,7 +53,7 @@ public:
// Check graph name uniqueness
if (!MCPUtils::AllGraphsNamed(BP, Graph).IsEmpty())
{
Result.Appendf(TEXT("ERROR: A graph named '%s' already exists in %s\n"), *Graph, *MCPUtils::FormatName(BP));
UMCPServer::Printf(TEXT("ERROR: A graph named '%s' already exists in %s\n"), *Graph, *MCPUtils::FormatName(BP));
return;
}
@@ -63,7 +64,7 @@ public:
{
if (CE->CustomFunctionName == FName(*Graph))
{
Result.Appendf(TEXT("ERROR: A custom event named '%s' already exists in %s\n"), *Graph, *MCPUtils::FormatName(BP));
UMCPServer::Printf(TEXT("ERROR: A custom event named '%s' already exists in %s\n"), *Graph, *MCPUtils::FormatName(BP));
return;
}
}
@@ -75,11 +76,11 @@ public:
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
if (!NewGraph)
{
Result.Append(TEXT("ERROR: Failed to create function graph\n"));
UMCPServer::Print(TEXT("ERROR: Failed to create function graph\n"));
return;
}
FBlueprintEditorUtils::AddFunctionGraph(BP, NewGraph, /*bIsUserCreated=*/true, /*SignatureFromObject=*/static_cast<UClass*>(nullptr));
Result.Appendf(TEXT("Created function graph: %s\n"), *MCPUtils::FormatName(NewGraph));
UMCPServer::Printf(TEXT("Created function graph: %s\n"), *MCPUtils::FormatName(NewGraph));
}
else if (GraphType == TEXT("macro"))
{
@@ -87,11 +88,11 @@ public:
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
if (!NewGraph)
{
Result.Append(TEXT("ERROR: Failed to create macro graph\n"));
UMCPServer::Print(TEXT("ERROR: Failed to create macro graph\n"));
return;
}
FBlueprintEditorUtils::AddMacroGraph(BP, NewGraph, /*bIsUserCreated=*/true, /*SignatureFromClass=*/nullptr);
Result.Appendf(TEXT("Created macro graph: %s\n"), *MCPUtils::FormatName(NewGraph));
UMCPServer::Printf(TEXT("Created macro graph: %s\n"), *MCPUtils::FormatName(NewGraph));
}
else // customEvent
{
@@ -100,7 +101,7 @@ public:
EventGraph = BP->UbergraphPages[0];
if (!EventGraph)
{
Result.Append(TEXT("ERROR: Blueprint has no EventGraph to add a custom event to\n"));
UMCPServer::Print(TEXT("ERROR: Blueprint has no EventGraph to add a custom event to\n"));
return;
}
@@ -111,7 +112,7 @@ public:
NewEvent->CreateNewGuid();
NewEvent->PostPlacedNewNode();
NewEvent->AllocateDefaultPins();
Result.Appendf(TEXT("Created custom event: %s\n"), *MCPUtils::FormatName(NewEvent));
UMCPServer::Printf(TEXT("Created custom event: %s\n"), *MCPUtils::FormatName(NewEvent));
}
MCPUtils::SaveBlueprintPackage(BP);

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
return TEXT("Delete a function or macro graph from a Blueprint. Cannot delete EventGraph pages.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
F.Walk(Path);
@@ -73,12 +74,12 @@ public:
{
if (G && MCPUtils::Identifies(Graph, G))
{
Result.Appendf(TEXT("ERROR: Cannot delete UbergraphPage '%s'. EventGraph pages cannot be deleted.\n"),
UMCPServer::Printf(TEXT("ERROR: Cannot delete UbergraphPage '%s'. EventGraph pages cannot be deleted.\n"),
*MCPUtils::FormatName(G));
return;
}
}
Result.Appendf(TEXT("ERROR: Graph '%s' not found in blueprint %s\n"),
UMCPServer::Printf(TEXT("ERROR: Graph '%s' not found in blueprint %s\n"),
*Graph, *MCPUtils::FormatName(BP));
return;
}
@@ -88,8 +89,8 @@ public:
FBlueprintEditorUtils::RemoveGraph(BP, TargetGraph, EGraphRemoveFlags::Default);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Deleted %s graph %s\n"), *GraphType, *GraphName);
UMCPServer::Printf(TEXT("Deleted %s graph %s\n"), *GraphType, *GraphName);
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed.\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed.\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
return TEXT("Rename a function or macro graph in a Blueprint. Cannot rename EventGraph pages.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraph* TargetGraph = F.Walk(Graph).Cast<UEdGraph>();
@@ -40,14 +41,14 @@ public:
UBlueprint* BP = Cast<UBlueprint>(TargetGraph->GetOuter());
if (!BP)
{
Result.Appendf(TEXT("Error: Graph '%s' is not owned by a Blueprint.\n"), *Graph);
UMCPServer::Printf(TEXT("Error: Graph '%s' is not owned by a Blueprint.\n"), *Graph);
return;
}
// Check if it's an UbergraphPage -- disallow rename
if (BP->UbergraphPages.Contains(TargetGraph))
{
Result.Appendf(TEXT("Error: Cannot rename UbergraphPage '%s'. EventGraph pages cannot be renamed.\n"),
UMCPServer::Printf(TEXT("Error: Cannot rename UbergraphPage '%s'. EventGraph pages cannot be renamed.\n"),
*MCPUtils::FormatName(TargetGraph));
return;
}
@@ -57,7 +58,7 @@ public:
bool bIsMacro = BP->MacroGraphs.Contains(TargetGraph);
if (!bIsFunction && !bIsMacro)
{
Result.Appendf(TEXT("Error: Graph '%s' is not a function or macro graph.\n"),
UMCPServer::Printf(TEXT("Error: Graph '%s' is not a function or macro graph.\n"),
*MCPUtils::FormatName(TargetGraph));
return;
}
@@ -67,7 +68,7 @@ public:
{
if (Existing != TargetGraph)
{
Result.Appendf(TEXT("Error: A graph named '%s' already exists in '%s'.\n"),
UMCPServer::Printf(TEXT("Error: A graph named '%s' already exists in '%s'.\n"),
*NewName, *MCPUtils::FormatName(BP));
return;
}
@@ -76,7 +77,7 @@ public:
FBlueprintEditorUtils::RenameGraph(TargetGraph, NewName);
MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Renamed to %s %s\n"),
UMCPServer::Printf(TEXT("Renamed to %s %s\n"),
bIsFunction ? TEXT("function") : TEXT("macro"),
*MCPUtils::FormatName(TargetGraph));
}

View File

@@ -40,7 +40,7 @@ public:
"Optionally attach it to an existing parent component.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -123,13 +123,13 @@ public:
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Added component %s (%s)"),
UMCPServer::Printf(TEXT("Added component %s (%s)"),
*MCPUtils::FormatName(NewNode->ComponentTemplate),
*MCPUtils::FormatName(ComponentClassObj));
if (ParentSCSNode)
{
Result.Appendf(TEXT(" under %s"), *MCPUtils::FormatName(ParentSCSNode->ComponentTemplate));
UMCPServer::Printf(TEXT(" under %s"), *MCPUtils::FormatName(ParentSCSNode->ComponentTemplate));
}
Result.Appendf(TEXT("\nSaved: %s\n"), bSaved ? TEXT("true") : TEXT("false"));
UMCPServer::Printf(TEXT("\nSaved: %s\n"), bSaved ? TEXT("true") : TEXT("false"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -49,7 +50,7 @@ public:
return TEXT("Create a new multicast event dispatcher on a Blueprint, optionally with parameters.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Path).Cast<UBlueprint>();
@@ -62,7 +63,7 @@ public:
{
if (Var.VarName == DispatcherFName)
{
Result.Appendf(TEXT("Error: A variable or dispatcher named '%s' already exists.\n"), *DispatcherName);
UMCPServer::Printf(TEXT("Error: A variable or dispatcher named '%s' already exists.\n"), *DispatcherName);
return;
}
}
@@ -70,7 +71,7 @@ public:
// Check against existing graphs (functions, macros, etc.)
if (!MCPUtils::AllGraphsNamed(BP, DispatcherName).IsEmpty())
{
Result.Appendf(TEXT("Error: A graph named '%s' already exists.\n"), *DispatcherName);
UMCPServer::Printf(TEXT("Error: A graph named '%s' already exists.\n"), *DispatcherName);
return;
}
@@ -79,7 +80,7 @@ public:
DelegateType.PinCategory = UEdGraphSchema_K2::PC_MCDelegate;
if (!FBlueprintEditorUtils::AddMemberVariable(BP, DispatcherFName, DelegateType))
{
Result.Appendf(TEXT("Error: Failed to add delegate variable for '%s'.\n"), *DispatcherName);
UMCPServer::Printf(TEXT("Error: Failed to add delegate variable for '%s'.\n"), *DispatcherName);
return;
}
@@ -90,7 +91,7 @@ public:
UEdGraph::StaticClass(), UEdGraphSchema_K2::StaticClass());
if (!SigGraph)
{
Result.Append(TEXT("Error: Failed to create delegate signature graph.\n"));
UMCPServer::Print(TEXT("Error: Failed to create delegate signature graph.\n"));
return;
}
@@ -116,7 +117,7 @@ public:
if (!EntryNode)
{
MCPUtils::SaveBlueprintPackage(BP);
Result.Append(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n"));
UMCPServer::Print(TEXT("Error: Event dispatcher created but entry node not found — parameters could not be added.\n"));
return;
}
@@ -137,9 +138,9 @@ public:
MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Created event dispatcher '%s'"), *DispatcherName);
UMCPServer::Printf(TEXT("Created event dispatcher '%s'"), *DispatcherName);
if (ParamCount > 0)
Result.Appendf(TEXT(" with %d parameter(s)"), ParamCount);
Result.Append(TEXT(".\n"));
UMCPServer::Printf(TEXT(" with %d parameter(s)"), ParamCount);
UMCPServer::Print(TEXT(".\n"));
}
};

View File

@@ -42,7 +42,7 @@ public:
return TEXT("Add a new parameter to a function, custom event, or event dispatcher in a Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -135,7 +135,7 @@ public:
EntryNode->CreateUserDefinedPin(FName(*ParamName), PinType, EGPD_Output);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Added %s parameter '%s' to %s '%s'%s\n"),
UMCPServer::Printf(TEXT("Added %s parameter '%s' to %s '%s'%s\n"),
*ParamType, *ParamName, *NodeType, *FunctionName,
bSaved ? TEXT("") : TEXT(" (WARNING: save failed)"));
}

View File

@@ -33,14 +33,14 @@ public:
"Creates stub function graphs for each interface function.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
UBlueprint* BP = Assets.Object();
// Resolve the interface class
UClass* InterfaceClass = FindInterfaceClass(InterfaceName, Result);
UClass* InterfaceClass = FindInterfaceClass(InterfaceName);
if (!InterfaceClass) return;
// Check for duplicates
@@ -64,15 +64,15 @@ public:
}
// Collect stub function graph names from the newly added interface entry
Result.Appendf(TEXT("Added interface %s\n"), *MCPUtils::FormatName(InterfaceClass));
Result.Appendf(TEXT("Function stubs:\n"));
UMCPServer::Printf(TEXT("Added interface %s\n"), *MCPUtils::FormatName(InterfaceClass));
UMCPServer::Printf(TEXT("Function stubs:\n"));
for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
{
if (IfaceDesc.Interface != InterfaceClass) continue;
for (const UEdGraph* Graph : IfaceDesc.Graphs)
{
if (Graph)
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Graph));
UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::FormatName(Graph));
}
break;
}
@@ -82,7 +82,7 @@ private:
// Resolve an interface name to a UClass. Tries loaded UInterface classes
// first (for native interfaces), then falls back to loading a Blueprint
// Interface asset.
static UClass* FindInterfaceClass(const FString& Name, FStringBuilderBase& Result)
static UClass* FindInterfaceClass(const FString& Name)
{
// Strategy 1: Search loaded UInterface classes by name
for (TObjectIterator<UClass> It; It; ++It)

View File

@@ -43,7 +43,7 @@ public:
return TEXT("Add a new member variable to a Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -80,13 +80,13 @@ public:
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Added %s %s to %s\n"),
UMCPServer::Printf(TEXT("Added %s %s to %s\n"),
*VariableType, *VariableName, *MCPUtils::FormatName(BP));
if (IsArray)
Result.Append(TEXT("Container: Array\n"));
UMCPServer::Print(TEXT("Container: Array\n"));
if (!Category.IsEmpty())
Result.Appendf(TEXT("Category: %s\n"), *Category);
UMCPServer::Printf(TEXT("Category: %s\n"), *Category);
if (!bSaved)
Result.Append(TEXT("Warning: package save failed\n"));
UMCPServer::Print(TEXT("Warning: package save failed\n"));
}
};

View File

@@ -45,7 +45,7 @@ public:
return TEXT("Change the type of an existing parameter on a function or custom event in a Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -123,14 +123,14 @@ public:
for (UEdGraphPin* Linked : Pin->LinkedTo)
{
if (!Linked || !Linked->GetOwningNode()) continue;
Result.Appendf(TEXT("Connection at risk: %s -> %s on %s\n"),
UMCPServer::Printf(TEXT("Connection at risk: %s -> %s on %s\n"),
*MCPUtils::FormatName(Pin),
*MCPUtils::FormatName(Linked),
*MCPUtils::FormatName(Linked->GetOwningNode()));
AtRisk++;
}
}
Result.Appendf(TEXT("Dry run: %d connection(s) at risk.\n"), AtRisk);
UMCPServer::Printf(TEXT("Dry run: %d connection(s) at risk.\n"), AtRisk);
return;
}
@@ -152,7 +152,7 @@ public:
// Save
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Changed '%s' to %s. Save %s.\n"),
UMCPServer::Printf(TEXT("Changed '%s' to %s. Save %s.\n"),
*ParamName, *MCPUtils::FormatPinType(NewPinType),
bSaved ? TEXT("succeeded") : TEXT("failed"));
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPAssets.h"
@@ -43,7 +44,7 @@ public:
"Supports dry-run mode to preview affected nodes before committing.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
@@ -62,10 +63,10 @@ public:
}
if (!Found)
{
Result.Appendf(TEXT("ERROR: Variable '%s' not found in %s.\nAvailable variables:\n"),
UMCPServer::Printf(TEXT("ERROR: Variable '%s' not found in %s.\nAvailable variables:\n"),
*Variable, *MCPUtils::FormatName(BP));
for (const FBPVariableDescription& Var : BP->NewVariables)
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Var));
UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::FormatName(Var));
return;
}
@@ -91,14 +92,14 @@ public:
for (auto* VarNode : NodeArray)
{
if (VarNode->GetVarName() != VarFName) continue;
Result.Appendf(TEXT(" %s %s in %s\n"), NodeType,
UMCPServer::Printf(TEXT(" %s %s in %s\n"), NodeType,
*MCPUtils::FormatName(static_cast<UEdGraphNode*>(VarNode)),
*MCPUtils::FormatName(VarNode->GetGraph()));
for (UEdGraphPin* Pin : VarNode->Pins)
{
if (!Pin || Pin->LinkedTo.Num() == 0) continue;
if (NodeType[0] == 'G' && Pin->Direction != EGPD_Output) continue; // Get nodes: only output pins
Result.Appendf(TEXT(" %s connected to %d pin(s)\n"),
UMCPServer::Printf(TEXT(" %s connected to %d pin(s)\n"),
*MCPUtils::FormatName(Pin), Pin->LinkedTo.Num());
}
}
@@ -114,13 +115,13 @@ public:
if (DryRun)
{
Result.Appendf(TEXT("Dry run: would change %s from %s to %s\n"),
UMCPServer::Printf(TEXT("Dry run: would change %s from %s to %s\n"),
*MCPUtils::FormatName(*Found),
*MCPUtils::FormatPinType(Found->VarType),
*MCPUtils::FormatPinType(NewPinType));
if (bHasAffected)
{
Result.Append(TEXT("Affected nodes:\n"));
UMCPServer::Print(TEXT("Affected nodes:\n"));
AppendAffectedNodes(GetNodes, TEXT("Get"));
AppendAffectedNodes(SetNodes, TEXT("Set"));
}
@@ -131,14 +132,14 @@ public:
Found->VarType = NewPinType;
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Changed %s to %s.%s\n"),
UMCPServer::Printf(TEXT("Changed %s to %s.%s\n"),
*MCPUtils::FormatName(*Found),
*MCPUtils::FormatPinType(NewPinType),
bSaved ? TEXT("") : TEXT(" WARNING: save failed."));
if (bHasAffected)
{
Result.Append(TEXT("Affected nodes:\n"));
UMCPServer::Print(TEXT("Affected nodes:\n"));
AppendAffectedNodes(GetNodes, TEXT("Get"));
AppendAffectedNodes(SetNodes, TEXT("Set"));
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -43,7 +44,7 @@ public:
// Compile a single blueprint and append results to Out.
// Returns true if the blueprint compiled cleanly (no errors).
static bool CompileAndReport(UBlueprint* BP, FStringBuilderBase& Out)
static bool CompileAndReport(UBlueprint* BP)
{
EBlueprintCompileOptions CompileOpts =
EBlueprintCompileOptions::SkipSave |
@@ -61,7 +62,7 @@ public:
if (!Node->bHasCompilerMessage) continue;
bool bIsError = (Node->ErrorType == EMessageSeverity::Error);
if (bIsError) ErrorCount++; else WarningCount++;
Out.Appendf(TEXT(" %s: [%s] %s > %s: %s\n"),
UMCPServer::Printf(TEXT(" %s: [%s] %s > %s: %s\n"),
bIsError ? TEXT("ERROR") : TEXT("WARNING"),
*MCPUtils::FormatName(Node->GetGraph()),
*MCPUtils::FormatName(Node),
@@ -74,18 +75,18 @@ public:
if (bIsValid && WarningCount == 0)
{
Out.Appendf(TEXT(" OK (status: %s)\n"), *StatusStr);
UMCPServer::Printf(TEXT(" OK (status: %s)\n"), *StatusStr);
}
else
{
Out.Appendf(TEXT(" status: %s, errors: %d, warnings: %d\n"),
UMCPServer::Printf(TEXT(" status: %s, errors: %d, warnings: %d\n"),
*StatusStr, ErrorCount, WarningCount);
}
return bIsValid;
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Finder;
Finder.Scan<UBlueprint>().Scan<UWorld>();
@@ -104,7 +105,7 @@ public:
// countOnly: return count without compiling anything
if (CountOnly)
{
Result.Appendf(TEXT("Matching blueprints: %d\n"), TotalMatching);
UMCPServer::Printf(TEXT("Matching blueprints: %d\n"), TotalMatching);
return;
}
@@ -131,12 +132,12 @@ public:
UBlueprint* BP = Loader.Object();
TotalChecked++;
Result.Appendf(TEXT("%s:\n"), *MCPUtils::FormatName(BP));
bool bValid = CompileAndReport(BP, Result);
UMCPServer::Printf(TEXT("%s:\n"), *MCPUtils::FormatName(BP));
bool bValid = CompileAndReport(BP);
if (bValid) TotalPassed++; else TotalFailed++;
}
Result.Appendf(TEXT("\nSummary: %d checked, %d passed, %d failed (of %d matching)\n"),
UMCPServer::Printf(TEXT("\nSummary: %d checked, %d passed, %d failed (of %d matching)\n"),
TotalChecked, TotalPassed, TotalFailed, TotalMatching);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -34,7 +35,7 @@ public:
return TEXT("Create a new Blueprint asset with a specified parent class and type.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -93,11 +94,11 @@ public:
bool bSaved = MCPUtils::SaveBlueprintPackage(NewBP);
// Report result
Result.Appendf(TEXT("Created: %s\n"), *MCPUtils::FormatName(NewBP));
Result.Appendf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentClassObj));
UMCPServer::Printf(TEXT("Created: %s\n"), *MCPUtils::FormatName(NewBP));
UMCPServer::Printf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentClassObj));
if (!bSaved)
Result.Append(TEXT("Warning: save failed\n"));
UMCPServer::Print(TEXT("Warning: save failed\n"));
for (UEdGraph* Graph : MCPUtils::AllGraphs(NewBP))
Result.Appendf(TEXT("Graph: %s\n"), *MCPUtils::FormatName(Graph));
UMCPServer::Printf(TEXT("Graph: %s\n"), *MCPUtils::FormatName(Graph));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -37,7 +38,7 @@ public:
"finding divergence after copy-paste, or auditing consistency.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load both blueprints
MCPAssets<UBlueprint> AssetsA;
@@ -89,13 +90,13 @@ public:
if (!pGA)
{
Result.Appendf(TEXT("Graph %s: only in B (%d nodes)\n"), *GraphName, (*pGB)->Nodes.Num());
UMCPServer::Printf(TEXT("Graph %s: only in B (%d nodes)\n"), *GraphName, (*pGB)->Nodes.Num());
TotalDiffs++;
continue;
}
if (!pGB)
{
Result.Appendf(TEXT("Graph %s: only in A (%d nodes)\n"), *GraphName, (*pGA)->Nodes.Num());
UMCPServer::Printf(TEXT("Graph %s: only in A (%d nodes)\n"), *GraphName, (*pGA)->Nodes.Num());
TotalDiffs++;
continue;
}
@@ -181,32 +182,32 @@ public:
if (bIdentical)
{
Result.Appendf(TEXT("Graph %s: identical (%d nodes)\n"), *GraphName, GA->Nodes.Num());
UMCPServer::Printf(TEXT("Graph %s: identical (%d nodes)\n"), *GraphName, GA->Nodes.Num());
continue;
}
TotalDiffs++;
Result.Appendf(TEXT("Graph %s: different (A=%d nodes, B=%d nodes)\n"), *GraphName, GA->Nodes.Num(), GB->Nodes.Num());
UMCPServer::Printf(TEXT("Graph %s: different (A=%d nodes, B=%d nodes)\n"), *GraphName, GA->Nodes.Num(), GB->Nodes.Num());
if (!OnlyInA.IsEmpty())
{
Result.Append(TEXT(" Nodes only in A:\n"));
for (const FString& Line : OnlyInA) Result.Appendf(TEXT(" %s\n"), *Line);
UMCPServer::Print(TEXT(" Nodes only in A:\n"));
for (const FString& Line : OnlyInA) UMCPServer::Printf(TEXT(" %s\n"), *Line);
}
if (!OnlyInB.IsEmpty())
{
Result.Append(TEXT(" Nodes only in B:\n"));
for (const FString& Line : OnlyInB) Result.Appendf(TEXT(" %s\n"), *Line);
UMCPServer::Print(TEXT(" Nodes only in B:\n"));
for (const FString& Line : OnlyInB) UMCPServer::Printf(TEXT(" %s\n"), *Line);
}
if (!ConnsOnlyInA.IsEmpty())
{
Result.Append(TEXT(" Connections only in A:\n"));
for (const FString& Line : ConnsOnlyInA) Result.Appendf(TEXT(" %s\n"), *Line);
UMCPServer::Print(TEXT(" Connections only in A:\n"));
for (const FString& Line : ConnsOnlyInA) UMCPServer::Printf(TEXT(" %s\n"), *Line);
}
if (!ConnsOnlyInB.IsEmpty())
{
Result.Append(TEXT(" Connections only in B:\n"));
for (const FString& Line : ConnsOnlyInB) Result.Appendf(TEXT(" %s\n"), *Line);
UMCPServer::Print(TEXT(" Connections only in B:\n"));
for (const FString& Line : ConnsOnlyInB) UMCPServer::Printf(TEXT(" %s\n"), *Line);
}
}
@@ -225,17 +226,17 @@ public:
if (!VarsOnlyInA.IsEmpty())
{
Result.Append(TEXT("Variables only in A:\n"));
for (const FString& Name : VarsOnlyInA) Result.Appendf(TEXT(" %s\n"), *Name);
UMCPServer::Print(TEXT("Variables only in A:\n"));
for (const FString& Name : VarsOnlyInA) UMCPServer::Printf(TEXT(" %s\n"), *Name);
TotalDiffs += VarsOnlyInA.Num();
}
if (!VarsOnlyInB.IsEmpty())
{
Result.Append(TEXT("Variables only in B:\n"));
for (const FString& Name : VarsOnlyInB) Result.Appendf(TEXT(" %s\n"), *Name);
UMCPServer::Print(TEXT("Variables only in B:\n"));
for (const FString& Name : VarsOnlyInB) UMCPServer::Printf(TEXT(" %s\n"), *Name);
TotalDiffs += VarsOnlyInB.Num();
}
Result.Appendf(TEXT("Total differences: %d\n"), TotalDiffs);
UMCPServer::Printf(TEXT("Total differences: %d\n"), TotalDiffs);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -31,46 +32,46 @@ public:
"and graph names. Does not include graph contents (use DumpGraphs for that).");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
if (!BP) return;
// Header
Result.Appendf(TEXT("Blueprint: %s\n"), *MCPUtils::FormatName(BP));
Result.Appendf(TEXT("Parent: %s\n"), BP->ParentClass ? *MCPUtils::FormatName(BP->ParentClass) : TEXT("None"));
Result.Appendf(TEXT("Type: %s\n"),
UMCPServer::Printf(TEXT("Blueprint: %s\n"), *MCPUtils::FormatName(BP));
UMCPServer::Printf(TEXT("Parent: %s\n"), BP->ParentClass ? *MCPUtils::FormatName(BP->ParentClass) : TEXT("None"));
UMCPServer::Printf(TEXT("Type: %s\n"),
*MCPUtils::EnumToString(BP->BlueprintType));
// Animation Blueprint
if (UAnimBlueprint* AnimBP = Cast<UAnimBlueprint>(BP))
{
if (AnimBP->TargetSkeleton)
Result.Appendf(TEXT("TargetSkeleton: %s\n"), *AnimBP->TargetSkeleton->GetPathName());
UMCPServer::Printf(TEXT("TargetSkeleton: %s\n"), *AnimBP->TargetSkeleton->GetPathName());
}
// Interfaces
for (const FBPInterfaceDescription& I : BP->ImplementedInterfaces)
{
if (I.Interface)
Result.Appendf(TEXT("Interface: %s\n"), *MCPUtils::FormatName(I.Interface));
UMCPServer::Printf(TEXT("Interface: %s\n"), *MCPUtils::FormatName(I.Interface));
}
// Variables
if (!BP->NewVariables.IsEmpty())
{
Result.Append(TEXT("\nVariables:\n"));
UMCPServer::Print(TEXT("\nVariables:\n"));
for (const FBPVariableDescription& V : BP->NewVariables)
{
Result.Appendf(TEXT(" %s %s"),
UMCPServer::Printf(TEXT(" %s %s"),
*MCPUtils::FormatPinType(V.VarType),
*MCPUtils::FormatName(V));
if (!V.DefaultValue.IsEmpty())
Result.Appendf(TEXT(" = %s"), *V.DefaultValue);
UMCPServer::Printf(TEXT(" = %s"), *V.DefaultValue);
if (!V.Category.IsEmpty() && V.Category.ToString() != TEXT("Default"))
Result.Appendf(TEXT(" [%s]"), *V.Category.ToString());
Result.Append(TEXT("\n"));
UMCPServer::Printf(TEXT(" [%s]"), *V.Category.ToString());
UMCPServer::Print(TEXT("\n"));
}
}
@@ -80,16 +81,16 @@ public:
const TArray<USCS_Node*>& AllNodes = SCS->GetAllNodes();
if (!AllNodes.IsEmpty())
{
Result.Append(TEXT("\nComponents:\n"));
UMCPServer::Print(TEXT("\nComponents:\n"));
for (USCS_Node* Node : AllNodes)
{
if (!Node || !Node->ComponentTemplate) continue;
Result.Appendf(TEXT(" %s (%s)"),
UMCPServer::Printf(TEXT(" %s (%s)"),
*MCPUtils::FormatName(Node->ComponentTemplate),
*MCPUtils::FormatName(Node->ComponentClass));
if (Node->ParentComponentOrVariableName != NAME_None)
Result.Appendf(TEXT(" parent=%s"), *Node->ParentComponentOrVariableName.ToString());
Result.Append(TEXT("\n"));
UMCPServer::Printf(TEXT(" parent=%s"), *Node->ParentComponentOrVariableName.ToString());
UMCPServer::Print(TEXT("\n"));
}
}
}
@@ -98,9 +99,9 @@ public:
TArray<UEdGraph*> Graphs = MCPUtils::AllGraphs(BP);
if (!Graphs.IsEmpty())
{
Result.Append(TEXT("\nGraphs:\n"));
UMCPServer::Print(TEXT("\nGraphs:\n"));
for (UEdGraph* Graph : Graphs)
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Graph));
UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::FormatName(Graph));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -29,7 +30,7 @@ public:
"showing hierarchy and component classes.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
F.Walk(Path);
@@ -41,7 +42,7 @@ public:
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
if (!SCS)
{
Result.Append(TEXT("ERROR: Not an Actor Blueprint (no SimpleConstructionScript)\n"));
UMCPServer::Print(TEXT("ERROR: Not an Actor Blueprint (no SimpleConstructionScript)\n"));
return;
}
@@ -50,11 +51,11 @@ public:
if (AllNodes.Num() == 0)
{
Result.Append(TEXT("No components.\n"));
UMCPServer::Print(TEXT("No components.\n"));
return;
}
Result.Append(TEXT("WARNING: This only lists components added in this blueprint's SCS. "
UMCPServer::Print(TEXT("WARNING: This only lists components added in this blueprint's SCS. "
"It does not include inherited components from C++ parent classes "
"(available via the CDO's OwnedComponents) or from parent blueprint SCS nodes.\n"));
@@ -62,34 +63,34 @@ public:
for (USCS_Node* Root : RootNodes)
{
if (!Root) continue;
EmitNode(Root, 0, Root == RootNodes[0], Result);
EmitNode(Root, 0, Root == RootNodes[0]);
}
}
private:
void EmitNode(USCS_Node* Node, int32 Depth, bool bIsSceneRoot, FStringBuilderBase& Result)
void EmitNode(USCS_Node* Node, int32 Depth, bool bIsSceneRoot)
{
// Indent to show hierarchy
for (int32 i = 0; i < Depth; i++)
Result.Append(TEXT(" "));
UMCPServer::Print(TEXT(" "));
FString ClassName = Node->ComponentClass
? MCPUtils::FormatName(Node->ComponentClass)
: TEXT("None");
Result.Appendf(TEXT("%s %s"),
UMCPServer::Printf(TEXT("%s %s"),
*ClassName,
*MCPUtils::FormatName(Node->ComponentTemplate));
if (bIsSceneRoot && Depth == 0)
Result.Append(TEXT(" [SceneRoot]"));
UMCPServer::Print(TEXT(" [SceneRoot]"));
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
for (USCS_Node* Child : Node->GetChildNodes())
{
if (!Child) continue;
EmitNode(Child, Depth + 1, false, Result);
EmitNode(Child, Depth + 1, false);
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
return TEXT("List all event dispatchers on a Blueprint, including their parameter signatures.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Path).Cast<UBlueprint>();
@@ -42,7 +43,7 @@ public:
for (const FName& DelegateName : DelegateNameSet)
{
Result.Appendf(TEXT("%s("), *DelegateName.ToString());
UMCPServer::Printf(TEXT("%s("), *DelegateName.ToString());
UEdGraph* SigGraph = FBlueprintEditorUtils::GetDelegateSignatureGraphByName(BP, DelegateName);
if (SigGraph)
@@ -53,9 +54,9 @@ public:
for (const TSharedPtr<FUserPinInfo>& PinInfo : FE->UserDefinedPins)
{
if (!PinInfo.IsValid()) continue;
if (!bFirst) Result.Append(TEXT(", "));
if (!bFirst) UMCPServer::Print(TEXT(", "));
bFirst = false;
Result.Appendf(TEXT("%s %s"),
UMCPServer::Printf(TEXT("%s %s"),
*MCPUtils::FormatPinType(PinInfo->PinType),
*PinInfo->PinName.ToString());
}
@@ -63,12 +64,12 @@ public:
}
}
Result.Append(TEXT(")\n"));
UMCPServer::Print(TEXT(")\n"));
}
if (DelegateNameSet.Num() == 0)
{
Result.Append(TEXT("No event dispatchers found.\n"));
UMCPServer::Print(TEXT("No event dispatchers found.\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -27,7 +28,7 @@ public:
"including their function graphs.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
F.Walk(Path);
@@ -41,17 +42,17 @@ public:
if (!IfaceDesc.Interface) continue;
bAny = true;
Result.Appendf(TEXT("Interface: %s\n"), *MCPUtils::FormatName(IfaceDesc.Interface));
UMCPServer::Printf(TEXT("Interface: %s\n"), *MCPUtils::FormatName(IfaceDesc.Interface));
for (const UEdGraph* Graph : IfaceDesc.Graphs)
{
if (!Graph) continue;
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Graph));
UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::FormatName(Graph));
}
}
if (!bAny)
{
Result.Append(TEXT("No interfaces implemented.\n"));
UMCPServer::Print(TEXT("No interfaces implemented.\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
"Reports compiler warnings and errors.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load Blueprint
MCPAssets<UBlueprint> Assets;
@@ -61,24 +62,24 @@ public:
}
// Summary
Result.Appendf(TEXT("Refreshed %s: %d graphs, %d nodes"), *MCPUtils::FormatName(BP), GraphCount, NodeCount);
UMCPServer::Printf(TEXT("Refreshed %s: %d graphs, %d nodes"), *MCPUtils::FormatName(BP), GraphCount, NodeCount);
if (OrphanedPinsRemoved > 0)
{
Result.Appendf(TEXT(", %d orphaned pins removed"), OrphanedPinsRemoved);
UMCPServer::Printf(TEXT(", %d orphaned pins removed"), OrphanedPinsRemoved);
}
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
// Collect compiler warnings and errors
if (BP->Status == BS_Error)
{
Result.Append(TEXT("ERROR: Blueprint has compiler errors after refresh\n"));
UMCPServer::Print(TEXT("ERROR: Blueprint has compiler errors after refresh\n"));
}
for (UEdGraphNode* Node : MCPUtils::AllNodes(BP))
{
if (!Node->bHasCompilerMessage) continue;
const TCHAR* Prefix = (Node->ErrorType == EMessageSeverity::Error) ? TEXT("ERROR") : TEXT("WARNING");
Result.Appendf(TEXT("%s: [%s] %s: %s\n"),
UMCPServer::Printf(TEXT("%s: [%s] %s: %s\n"),
Prefix, *MCPUtils::FormatName(Node->GetGraph()),
*MCPUtils::FormatName(Node), *Node->ErrorMsg);
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
return TEXT("Remove a component from a Blueprint's SimpleConstructionScript.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
@@ -40,7 +41,7 @@ public:
USimpleConstructionScript* SCS = BP->SimpleConstructionScript;
if (!SCS)
{
Result.Append(TEXT("ERROR: Not an Actor Blueprint (no SimpleConstructionScript).\n"));
UMCPServer::Print(TEXT("ERROR: Not an Actor Blueprint (no SimpleConstructionScript).\n"));
return;
}
@@ -59,12 +60,12 @@ public:
if (!NodeToRemove)
{
Result.Appendf(TEXT("ERROR: Component '%s' not found.\nAvailable components:\n"),
UMCPServer::Printf(TEXT("ERROR: Component '%s' not found.\nAvailable components:\n"),
*Component);
for (USCS_Node* Node : AllNodes)
{
if (Node && Node->ComponentTemplate)
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Node->ComponentTemplate));
UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::FormatName(Node->ComponentTemplate));
}
return;
}
@@ -73,7 +74,7 @@ public:
const TArray<USCS_Node*>& RootNodes = SCS->GetRootNodes();
if (RootNodes.Contains(NodeToRemove) && NodeToRemove->GetChildNodes().Num() > 0)
{
Result.Appendf(TEXT("ERROR: Cannot remove '%s' — it is a root component with %d child(ren). "
UMCPServer::Printf(TEXT("ERROR: Cannot remove '%s' — it is a root component with %d child(ren). "
"Remove or re-parent the children first.\n"),
*MCPUtils::FormatName(NodeToRemove->ComponentTemplate),
NodeToRemove->GetChildNodes().Num());
@@ -87,7 +88,7 @@ public:
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Removed component %s.%s\n"),
UMCPServer::Printf(TEXT("Removed component %s.%s\n"),
*RemovedName,
bSaved ? TEXT("") : TEXT(" WARNING: save failed."));
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPAssets.h"
@@ -36,7 +37,7 @@ public:
return TEXT("Remove a parameter from a function or custom event in a Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -68,11 +69,11 @@ public:
if (!EntryNode)
{
Result.Appendf(TEXT("Error: Function or event '%s' not found.\nAvailable:\n"), *FunctionName);
UMCPServer::Printf(TEXT("Error: Function or event '%s' not found.\nAvailable:\n"), *FunctionName);
for (UK2Node_FunctionEntry* FE : MCPUtils::AllNodes<UK2Node_FunctionEntry>(BP))
Result.Appendf(TEXT(" function: %s\n"), *MCPUtils::FormatName(FE->GetGraph()));
UMCPServer::Printf(TEXT(" function: %s\n"), *MCPUtils::FormatName(FE->GetGraph()));
for (UK2Node_CustomEvent* CE : MCPUtils::AllNodes<UK2Node_CustomEvent>(BP))
Result.Appendf(TEXT(" event: %s\n"), *MCPUtils::FormatName(CE));
UMCPServer::Printf(TEXT(" event: %s\n"), *MCPUtils::FormatName(CE));
return;
}
@@ -90,11 +91,11 @@ public:
if (RemovedIndex == INDEX_NONE)
{
Result.Appendf(TEXT("Error: Parameter '%s' not found on %s.\nAvailable:\n"),
UMCPServer::Printf(TEXT("Error: Parameter '%s' not found on %s.\nAvailable:\n"),
*ParamName, *MCPUtils::FormatName(EntryNode));
for (const TSharedPtr<FUserPinInfo>& PinInfo : EntryNode->UserDefinedPins)
if (PinInfo.IsValid())
Result.Appendf(TEXT(" %s\n"), *PinInfo->PinName.ToString());
UMCPServer::Printf(TEXT(" %s\n"), *PinInfo->PinName.ToString());
return;
}
@@ -108,8 +109,8 @@ public:
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Removed parameter '%s' from %s.\n"), *ParamName, *MCPUtils::FormatName(EntryNode));
UMCPServer::Printf(TEXT("Removed parameter '%s' from %s.\n"), *ParamName, *MCPUtils::FormatName(EntryNode));
if (!bSaved)
Result.Append(TEXT("Warning: save failed.\n"));
UMCPServer::Print(TEXT("Warning: save failed.\n"));
}
};

View File

@@ -35,7 +35,7 @@ public:
"Optionally preserve the function graphs as regular functions.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -67,8 +67,8 @@ public:
FTopLevelAssetPath InterfacePath = FoundInterface->GetClassPathName();
FBlueprintEditorUtils::RemoveInterface(BP, InterfacePath, PreserveFunctions);
Result.Appendf(TEXT("Removed interface %s\n"), *MCPUtils::FormatName(FoundInterface));
UMCPServer::Printf(TEXT("Removed interface %s\n"), *MCPUtils::FormatName(FoundInterface));
if (PreserveFunctions)
Result.Append(TEXT("Function graphs preserved as regular functions.\n"));
UMCPServer::Print(TEXT("Function graphs preserved as regular functions.\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -30,7 +31,7 @@ public:
return TEXT("Remove a member variable from a Blueprint.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
@@ -50,11 +51,11 @@ public:
if (!Found)
{
Result.Appendf(TEXT("ERROR: Variable '%s' not found in %s.\nAvailable variables:\n"),
UMCPServer::Printf(TEXT("ERROR: Variable '%s' not found in %s.\nAvailable variables:\n"),
*VariableName, *MCPUtils::FormatName(BP));
for (const FBPVariableDescription& Var : BP->NewVariables)
{
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Var));
UMCPServer::Printf(TEXT(" %s\n"), *MCPUtils::FormatName(Var));
}
return;
}
@@ -65,7 +66,7 @@ public:
FBlueprintEditorUtils::RemoveMemberVariable(BP, VarFName);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Removed variable %s from %s.%s\n"),
UMCPServer::Printf(TEXT("Removed variable %s from %s.%s\n"),
*VarFName.ToString(), *MCPUtils::FormatName(BP),
bSaved ? TEXT("") : TEXT(" WARNING: save failed."));
}

View File

@@ -33,7 +33,7 @@ public:
return TEXT("Change a Blueprint's parent class. Accepts C++ class names or Blueprint names.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load Blueprint
MCPAssets<UBlueprint> Assets;
@@ -66,9 +66,9 @@ public:
FKismetEditorUtilities::CompileBlueprint(BP);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Reparented %s: %s -> %s\n"),
UMCPServer::Printf(TEXT("Reparented %s: %s -> %s\n"),
*MCPUtils::FormatName(BP), *OldParentName, *MCPUtils::FormatName(NewParentClassObj));
if (!bSaved)
Result.Append(TEXT("Warning: save failed\n"));
UMCPServer::Print(TEXT("Warning: save failed\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -36,7 +37,7 @@ public:
return TEXT("List all Blueprint assets in the project, with optional filtering by name, parent class, or type.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UObject> Assets;
Assets.NoScans().Substring(Query).Limit(500);
@@ -73,13 +74,13 @@ public:
}
}
Result.Appendf(TEXT("%30s %s\n"), *ParentClassName, *Asset.PackageName.ToString());
UMCPServer::Printf(TEXT("%30s %s\n"), *ParentClassName, *Asset.PackageName.ToString());
Count++;
}
if (Count == 0)
{
Result.Append(TEXT("No blueprint assets found.\n"));
UMCPServer::Print(TEXT("No blueprint assets found.\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -41,7 +42,7 @@ public:
return TEXT("Search across all Blueprint graphs for nodes matching a query string.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
int32 Limit = (MaxResults > 0) ? FMath::Clamp(MaxResults, 1, 200) : 50;
int32 Count = 0;
@@ -85,15 +86,15 @@ public:
if (!bMatch) continue;
Count++;
Result.Appendf(TEXT("blueprint: %s\n"), *MCPUtils::FormatName(BP));
Result.Appendf(TEXT(" graph: %s\n"), *MCPUtils::FormatName(Node->GetGraph()));
Result.Appendf(TEXT(" node: %s\n"), *MCPUtils::FormatName(Node));
Result.Appendf(TEXT(" class: %s\n"), *MCPUtils::FormatName(Node->GetClass()));
if (!FuncName.IsEmpty()) Result.Appendf(TEXT(" function: %s\n"), *FuncName);
if (!EventName.IsEmpty()) Result.Appendf(TEXT(" event: %s\n"), *EventName);
if (!VarName.IsEmpty()) Result.Appendf(TEXT(" variable: %s\n"), *VarName);
if (bIsLevelBP) Result.Append(TEXT(" level-blueprint: true\n"));
Result.Append(TEXT("\n"));
UMCPServer::Printf(TEXT("blueprint: %s\n"), *MCPUtils::FormatName(BP));
UMCPServer::Printf(TEXT(" graph: %s\n"), *MCPUtils::FormatName(Node->GetGraph()));
UMCPServer::Printf(TEXT(" node: %s\n"), *MCPUtils::FormatName(Node));
UMCPServer::Printf(TEXT(" class: %s\n"), *MCPUtils::FormatName(Node->GetClass()));
if (!FuncName.IsEmpty()) UMCPServer::Printf(TEXT(" function: %s\n"), *FuncName);
if (!EventName.IsEmpty()) UMCPServer::Printf(TEXT(" event: %s\n"), *EventName);
if (!VarName.IsEmpty()) UMCPServer::Printf(TEXT(" variable: %s\n"), *VarName);
if (bIsLevelBP) UMCPServer::Print(TEXT(" level-blueprint: true\n"));
UMCPServer::Print(TEXT("\n"));
}
};
@@ -120,7 +121,7 @@ public:
SearchBlueprint(LevelBP, true);
}
Result.Appendf(TEXT("Results: %d\n"), Count);
if (Count >= Limit) Result.Appendf(TEXT("(limit %d reached, use MaxResults to increase)\n"), Limit);
UMCPServer::Printf(TEXT("Results: %d\n"), Count);
if (Count >= Limit) UMCPServer::Printf(TEXT("(limit %d reached, use MaxResults to increase)\n"), Limit);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "UObject/UObjectIterator.h"
@@ -36,7 +37,7 @@ public:
"Returns class names, parent class, package, and flags.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
Limit = FMath::Clamp(Limit, 1, 500);
@@ -53,7 +54,7 @@ public:
}
if (!ParentClassObj)
{
Result.Appendf(TEXT("Error: Parent class '%s' not found\n"), *ParentClass);
UMCPServer::Printf(TEXT("Error: Parent class '%s' not found\n"), *ParentClass);
return;
}
}
@@ -78,16 +79,16 @@ public:
}
}
Result.Appendf(TEXT("Found %d classes"), TotalMatched);
UMCPServer::Printf(TEXT("Found %d classes"), TotalMatched);
if (TotalMatched > Limit)
{
Result.Appendf(TEXT(" (showing %d)"), Limit);
UMCPServer::Printf(TEXT(" (showing %d)"), Limit);
}
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
for (UClass* Class : Matches)
{
Result.Appendf(TEXT(" %s"), *MCPUtils::FormatName(Class));
UMCPServer::Printf(TEXT(" %s"), *MCPUtils::FormatName(Class));
// Flags
TStringBuilder<64> Flags;
@@ -97,15 +98,15 @@ public:
if (Class->ClassGeneratedBy) Flags.Append(TEXT(" Blueprint"));
if (Flags.Len() > 0)
{
Result.Appendf(TEXT(" [%s]"), Flags.ToString() + 1); // skip leading space
UMCPServer::Printf(TEXT(" [%s]"), Flags.ToString() + 1); // skip leading space
}
if (Class->GetSuperClass())
{
Result.Appendf(TEXT(" : %s"), *MCPUtils::FormatName(Class->GetSuperClass()));
UMCPServer::Printf(TEXT(" : %s"), *MCPUtils::FormatName(Class->GetSuperClass()));
}
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "Class_ShowProperties.generated.h"
@@ -27,16 +28,16 @@ public:
return TEXT("List properties on a UClass, including type, owning class, and property flags.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
UClass* FoundClass = MCPUtils::FindClassByName(ClassName);
if (!FoundClass)
{
Result.Appendf(TEXT("ERROR: Class '%s' not found\n"), *ClassName);
UMCPServer::Printf(TEXT("ERROR: Class '%s' not found\n"), *ClassName);
return;
}
Result.Appendf(TEXT("Properties of %s:\n"), *MCPUtils::FormatName(FoundClass));
UMCPServer::Printf(TEXT("Properties of %s:\n"), *MCPUtils::FormatName(FoundClass));
int32 Count = 0;
for (TFieldIterator<FProperty> PropIt(FoundClass); PropIt; ++PropIt)
@@ -61,18 +62,18 @@ public:
if (Prop->HasAnyPropertyFlags(CPF_RepNotify)) Flags.Append(TEXT(" RepNotify"));
UClass* OwnerClass = Prop->GetOwnerClass();
Result.Appendf(TEXT(" %s %s"), *MCPUtils::FormatPropertyType(Prop), *PropName);
UMCPServer::Printf(TEXT(" %s %s"), *MCPUtils::FormatPropertyType(Prop), *PropName);
if (OwnerClass && OwnerClass != FoundClass)
Result.Appendf(TEXT(" [%s]"), *MCPUtils::FormatName(OwnerClass));
UMCPServer::Printf(TEXT(" [%s]"), *MCPUtils::FormatName(OwnerClass));
if (Flags.Len() > 0)
Result.Appendf(TEXT(" (%s)"), Flags.ToString() + 1); // skip leading space
Result.Append(TEXT("\n"));
UMCPServer::Printf(TEXT(" (%s)"), Flags.ToString() + 1); // skip leading space
UMCPServer::Print(TEXT("\n"));
Count++;
}
if (Count == 0)
{
Result.Append(TEXT("No properties found.\n"));
UMCPServer::Print(TEXT("No properties found.\n"));
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "Editor.h"
#include "Subsystems/AssetEditorSubsystem.h"
@@ -22,19 +23,19 @@ public:
return TEXT("List all currently open asset editors, showing which has focus and whether they have unsaved changes.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
UAssetEditorSubsystem* Sub = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
if (!Sub)
{
Result.Append(TEXT("Error: AssetEditorSubsystem not available\n"));
UMCPServer::Print(TEXT("Error: AssetEditorSubsystem not available\n"));
return;
}
TArray<UObject*> EditedAssets = Sub->GetAllEditedAssets();
if (EditedAssets.IsEmpty())
{
Result.Append(TEXT("No asset editors are open.\n"));
UMCPServer::Print(TEXT("No asset editors are open.\n"));
return;
}
@@ -42,7 +43,7 @@ public:
{
bool bDirty = Asset->GetOutermost()->IsDirty();
Result.Appendf(TEXT(" %s%s\n"),
UMCPServer::Printf(TEXT(" %s%s\n"),
bDirty ? TEXT("[unsaved] ") : TEXT(""),
*Asset->GetPathName());
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "Editor.h"
@@ -26,7 +27,7 @@ public:
return TEXT("Open an asset in its editor and bring it to focus.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UObject* Obj = F.Walk(Path).Cast<UObject>();
@@ -35,13 +36,13 @@ public:
UAssetEditorSubsystem* Sub = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>();
if (!Sub)
{
Result.Append(TEXT("Error: AssetEditorSubsystem not available\n"));
UMCPServer::Print(TEXT("Error: AssetEditorSubsystem not available\n"));
return;
}
if (Sub->OpenEditorForAsset(Obj))
Result.Appendf(TEXT("Opened editor for %s\n"), *Obj->GetPathName());
UMCPServer::Printf(TEXT("Opened editor for %s\n"), *Obj->GetPathName());
else
Result.Appendf(TEXT("Error: Could not open editor for %s\n"), *Obj->GetPathName());
UMCPServer::Printf(TEXT("Error: Could not open editor for %s\n"), *Obj->GetPathName());
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -32,7 +33,7 @@ public:
return TEXT("Create a new UserDefinedEnum asset with the specified values.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -64,8 +65,8 @@ public:
bool bSaved = MCPUtils::SaveGenericPackage(NewEnum);
Result.Appendf(TEXT("Created %s with %d values\n"), *NewEnum->GetPathName(), EnumValues.Num());
UMCPServer::Printf(TEXT("Created %s with %d values\n"), *NewEnum->GetPathName(), EnumValues.Num());
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -49,7 +50,7 @@ public:
"Use GraphNodeSearchTypes first to find the exact action name.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraph* TargetGraph = F.Walk(Graph).Cast<UEdGraph>();
@@ -68,13 +69,13 @@ public:
TArray<TSharedPtr<FEdGraphSchemaAction>> Matches = MCPUtils::SearchGraphActions(TargetGraph, Entry.ActionName, 0, /*ExactMatch=*/true);
if (Matches.Num() == 0)
{
Result.Appendf(TEXT("ERROR: No action found matching '%s'. Use GraphNodeSearchTypes to find available actions.\n"),
UMCPServer::Printf(TEXT("ERROR: No action found matching '%s'. Use GraphNodeSearchTypes to find available actions.\n"),
*Entry.ActionName);
continue;
}
if (Matches.Num() > 1)
{
Result.Appendf(TEXT("ERROR: Ambiguous: %d actions match '%s'.\n"),
UMCPServer::Printf(TEXT("ERROR: Ambiguous: %d actions match '%s'.\n"),
Matches.Num(), *Entry.ActionName);
continue;
}
@@ -84,18 +85,18 @@ public:
UEdGraphNode* NewNode = Matches[0]->PerformAction(TargetGraph, nullptr, Location, /*bSelectNewNode=*/false);
if (!NewNode)
{
Result.Appendf(TEXT("ERROR: PerformAction returned null for '%s'.\n"), *Entry.ActionName);
UMCPServer::Printf(TEXT("ERROR: PerformAction returned null for '%s'.\n"), *Entry.ActionName);
continue;
}
if (!NewNode->NodeGuid.IsValid())
NewNode->CreateNewGuid();
Result.Appendf(TEXT("Spawned: %s (%s)\n"),
UMCPServer::Printf(TEXT("Spawned: %s (%s)\n"),
*MCPUtils::FormatName(NewNode), *MCPUtils::FormatName(NewNode->GetClass()));
SuccessCount++;
}
Result.Appendf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount);
UMCPServer::Printf(TEXT("Spawned %d/%d nodes.\n"), SuccessCount, TotalCount);
}
};

View File

@@ -32,7 +32,7 @@ public:
"Cannot delete undeletable nodes (entry points, root nodes, etc).");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
@@ -63,6 +63,6 @@ public:
Graph->RemoveNode(FoundNode);
}
Result.Appendf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName);
UMCPServer::Printf(TEXT("Deleted node '%s' from graph '%s'.\n"), *NodeTitle, *GraphName);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -39,7 +40,7 @@ public:
"Connections are not preserved on the duplicates.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraph* TargetGraph = F.Walk(Graph).Cast<UEdGraph>();
@@ -47,7 +48,7 @@ public:
if (Nodes.Array.Num() == 0)
{
Result.Append(TEXT("ERROR: Nodes array is empty\n"));
UMCPServer::Print(TEXT("ERROR: Nodes array is empty\n"));
return;
}
@@ -67,7 +68,7 @@ public:
}
if (!Found)
{
Result.Appendf(TEXT("ERROR: Node '%s' not found in graph\n"), *Name);
UMCPServer::Printf(TEXT("ERROR: Node '%s' not found in graph\n"), *Name);
continue;
}
SourceNodes.Add(Found);
@@ -81,7 +82,7 @@ public:
UEdGraphNode* NewNode = DuplicateObject<UEdGraphNode>(SourceNode, TargetGraph);
if (!NewNode)
{
Result.Appendf(TEXT("ERROR: Failed to duplicate %s\n"), *MCPUtils::FormatName(SourceNode));
UMCPServer::Printf(TEXT("ERROR: Failed to duplicate %s\n"), *MCPUtils::FormatName(SourceNode));
continue;
}
@@ -96,7 +97,7 @@ public:
}
TargetGraph->AddNode(NewNode, false, false);
Result.Appendf(TEXT("Duplicated: %s -> %s\n"), *MCPUtils::FormatName(SourceNode), *MCPUtils::FormatName(NewNode));
UMCPServer::Printf(TEXT("Duplicated: %s -> %s\n"), *MCPUtils::FormatName(SourceNode), *MCPUtils::FormatName(NewNode));
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -26,14 +27,14 @@ public:
return TEXT("Get the comment text and bubble visibility of a node.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
if (!FoundNode) return;
Result.Appendf(TEXT("Node: %s\n"), *MCPUtils::FormatName(FoundNode));
Result.Appendf(TEXT("Comment: %s\n"), *FoundNode->NodeComment);
Result.Appendf(TEXT("BubbleVisible: %s\n"), FoundNode->bCommentBubbleVisible ? TEXT("true") : TEXT("false"));
UMCPServer::Printf(TEXT("Node: %s\n"), *MCPUtils::FormatName(FoundNode));
UMCPServer::Printf(TEXT("Comment: %s\n"), *FoundNode->NodeComment);
UMCPServer::Printf(TEXT("BubbleVisible: %s\n"), FoundNode->bCommentBubbleVisible ? TEXT("true") : TEXT("false"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -35,7 +36,7 @@ public:
"Returns full action names for use with GraphNodeCreate.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
int32 ClampedMax = FMath::Clamp(MaxResults, 1, 500);
@@ -47,16 +48,16 @@ public:
for (const TSharedPtr<FEdGraphSchemaAction>& Action : Actions)
{
Result.Appendf(TEXT("%s\n"), *MCPUtils::ActionFullName(Action));
UMCPServer::Printf(TEXT("%s\n"), *MCPUtils::ActionFullName(Action));
}
if (Actions.Num() == 0)
{
Result.Append(TEXT("No matching node types found.\n"));
UMCPServer::Print(TEXT("No matching node types found.\n"));
}
else if (Actions.Num() >= ClampedMax)
{
Result.Appendf(TEXT("WARNING: Reached limit of %d results. Refine your query or increase MaxResults.\n"), ClampedMax);
UMCPServer::Printf(TEXT("WARNING: Reached limit of %d results. Refine your query or increase MaxResults.\n"), ClampedMax);
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -29,7 +30,7 @@ public:
return TEXT("Set a node's comment text. Makes the comment bubble visible if non-empty.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
@@ -44,6 +45,6 @@ public:
FoundNode->bCommentBubblePinned = true;
}
Result.Appendf(TEXT("Comment set on %s\n"), *MCPUtils::FormatName(FoundNode));
UMCPServer::Printf(TEXT("Comment set on %s\n"), *MCPUtils::FormatName(FoundNode));
}
};

View File

@@ -53,8 +53,7 @@ public:
// K2 graphs: set pin default values.
// -----------------------------------------------------------------------
void HandleK2Entry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj, const UEdGraphSchema_K2* K2Schema,
FStringBuilderBase& Result)
void HandleK2Entry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj, const UEdGraphSchema_K2* K2Schema)
{
MCPFetcher F(GraphObj);
UEdGraphPin* Pin = F.Node(Entry.Node).Pin(Entry.Name).Cast<UEdGraphPin>();
@@ -64,7 +63,7 @@ public:
if (Pin->Direction != EGPD_Input)
{
Result.Appendf(TEXT("error: %s is an output pin\n"), *MCPUtils::FormatName(Pin));
UMCPServer::Printf(TEXT("error: %s is an output pin\n"), *MCPUtils::FormatName(Pin));
return;
}
@@ -77,7 +76,7 @@ public:
FString Error = K2Schema->IsPinDefaultValid(Pin, UseDefaultValue, UseDefaultObject, UseDefaultText);
if (!Error.IsEmpty())
{
Result.Appendf(TEXT("error: %s: %s\n"), *MCPUtils::FormatName(Pin), *Error);
UMCPServer::Printf(TEXT("error: %s: %s\n"), *MCPUtils::FormatName(Pin), *Error);
return;
}
UMCPServer::AddTouchedObject(Node);
@@ -88,8 +87,7 @@ public:
// Material graphs: set material expression properties.
// -----------------------------------------------------------------------
void HandleMaterialEntry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj,
FStringBuilderBase& Result)
void HandleMaterialEntry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj)
{
MCPFetcher F(GraphObj);
UEdGraphNode* Node = F.Node(Entry.Node).Cast<UEdGraphNode>();
@@ -106,7 +104,7 @@ public:
// -----------------------------------------------------------------------
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Fetch the graph once.
MCPFetcher GraphFetcher;
@@ -119,7 +117,7 @@ public:
if (!K2Schema && !MGSchema)
{
Result.Appendf(TEXT("error: unsupported graph schema %s\n"), *Schema->GetClass()->GetName());
UMCPServer::Printf(TEXT("error: unsupported graph schema %s\n"), *Schema->GetClass()->GetName());
return;
}
@@ -130,11 +128,11 @@ public:
continue;
if (K2Schema)
HandleK2Entry(Entry, GraphObj, K2Schema, Result);
HandleK2Entry(Entry, GraphObj, K2Schema);
else if (MGSchema)
HandleMaterialEntry(Entry, GraphObj, Result);
HandleMaterialEntry(Entry, GraphObj);
}
Result.Appendf(TEXT("Done.\n"));
UMCPServer::Printf(TEXT("Done.\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -46,7 +47,7 @@ public:
return TEXT("Reposition one or more nodes in a Blueprint graph.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UBlueprint* BP = F.Walk(Blueprint).Cast<UBlueprint>();
@@ -65,10 +66,10 @@ public:
Node->NodePosX = Entry.X;
Node->NodePosY = Entry.Y;
Result.Appendf(TEXT("Moved %s to (%d, %d)\n"), *MCPUtils::FormatName(Node), Entry.X, Entry.Y);
UMCPServer::Printf(TEXT("Moved %s to (%d, %d)\n"), *MCPUtils::FormatName(Node), Entry.X, Entry.Y);
SuccessCount++;
}
Result.Appendf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num());
UMCPServer::Printf(TEXT("Moved %d/%d nodes.\n"), SuccessCount, Nodes.Array.Num());
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -45,7 +46,7 @@ public:
return TEXT("Connect pins between nodes in a graph (Blueprint or Material).");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraph* G = F.Walk(Graph).ToGraph().Cast<UEdGraph>();
@@ -72,7 +73,7 @@ public:
const FPinConnectionResponse Response = Schema->CanCreateConnection(SourcePin, TargetPin);
if (Response.Response == CONNECT_RESPONSE_DISALLOW)
{
Result.Appendf(TEXT("error: Cannot connect %s.%s to %s.%s: %s\n"),
UMCPServer::Printf(TEXT("error: Cannot connect %s.%s to %s.%s: %s\n"),
*MCPUtils::FormatName(SourcePin->GetOwningNode()), *MCPUtils::FormatName(SourcePin),
*MCPUtils::FormatName(TargetPin->GetOwningNode()), *MCPUtils::FormatName(TargetPin),
*Response.Message.ToString());
@@ -83,6 +84,6 @@ public:
SuccessCount++;
}
Result.Appendf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount);
UMCPServer::Printf(TEXT("Connected %d/%d pins.\n"), SuccessCount, TotalCount);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -45,7 +46,7 @@ public:
"Can disconnect a specific link or all links on a pin.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UEdGraph* G = F.Walk(Graph).ToGraph().Cast<UEdGraph>();
@@ -73,7 +74,7 @@ public:
if (!Pin->LinkedTo.Contains(Target))
{
Result.Appendf(TEXT("Error: %s.%s is not connected to %s.%s\n"),
UMCPServer::Printf(TEXT("Error: %s.%s is not connected to %s.%s\n"),
*MCPUtils::FormatName(Pin->GetOwningNode()), *MCPUtils::FormatName(Pin),
*MCPUtils::FormatName(Target->GetOwningNode()), *MCPUtils::FormatName(Target));
continue;
@@ -91,14 +92,14 @@ public:
}
}
Result.Appendf(TEXT("Disconnected %d link(s) from %s.%s\n"),
UMCPServer::Printf(TEXT("Disconnected %d link(s) from %s.%s\n"),
DisconnectedCount,
*MCPUtils::FormatName(Pin->GetOwningNode()), *MCPUtils::FormatName(Pin));
SuccessCount++;
TotalDisconnected += DisconnectedCount;
}
Result.Appendf(TEXT("Done: %d/%d succeeded, %d links broken.\n"),
UMCPServer::Printf(TEXT("Done: %d/%d succeeded, %d links broken.\n"),
SuccessCount, Disconnections.Array.Num(), TotalDisconnected);
}
};

View File

@@ -32,7 +32,7 @@ public:
"If given a blueprint or material, dumps all graphs. If given a specific graph, dumps only that one.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
F.Walk(Path);

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -31,7 +32,7 @@ public:
return TEXT("Create a new UMaterialFunction asset with an optional description.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -46,8 +47,8 @@ public:
bool bSaved = MCPUtils::SaveGenericPackage(MF);
Result.Appendf(TEXT("Created %s\n"), *MF->GetPathName());
UMCPServer::Printf(TEXT("Created %s\n"), *MF->GetPathName());
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -36,7 +37,7 @@ public:
return TEXT("Remove a parameter override from a Material Instance, reverting it to the parent material's value.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
@@ -66,13 +67,13 @@ public:
if (Removed == 0)
{
Result.Appendf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"),
UMCPServer::Printf(TEXT("No override found for parameter '%s' (association=%s layer=%d) on %s"),
*Parameter, *ParameterAssociation, ParameterLayer, *MCPUtils::FormatName(MI));
return;
}
MCPUtils::SaveGenericPackage(MI);
Result.Appendf(TEXT("Cleared override for '%s' on %s\n"),
UMCPServer::Printf(TEXT("Cleared override for '%s' on %s\n"),
*Parameter, *MCPUtils::FormatName(MI));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -33,7 +34,7 @@ public:
return TEXT("Create a new Material Instance Constant asset with a specified parent material.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -63,7 +64,7 @@ public:
if (!ParentMaterialObj)
{
Result.Appendf(TEXT("ERROR: Parent material '%s' not found\n"), *ParentMaterial);
UMCPServer::Printf(TEXT("ERROR: Parent material '%s' not found\n"), *ParentMaterial);
return;
}
@@ -77,14 +78,14 @@ public:
// Save.
bool bSaved = MCPUtils::SaveGenericPackage(MI);
Result.Appendf(TEXT("Created %s\n"), *MI->GetPathName());
UMCPServer::Printf(TEXT("Created %s\n"), *MI->GetPathName());
if (UMaterialInstance* ParentMI = Cast<UMaterialInstance>(ParentMaterialObj))
Result.Appendf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentMI));
UMCPServer::Printf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentMI));
else if (UMaterial* ParentMat = Cast<UMaterial>(ParentMaterialObj))
Result.Appendf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentMat));
UMCPServer::Printf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentMat));
else
Result.Appendf(TEXT("Parent: %s\n"), *ParentMaterialObj->GetPathName());
UMCPServer::Printf(TEXT("Parent: %s\n"), *ParentMaterialObj->GetPathName());
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -27,7 +28,7 @@ public:
return TEXT("List all parameters on a Material Instance, showing current values and which are overridden.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
@@ -40,8 +41,8 @@ public:
for (auto& [Info, Meta] : AllParams)
{
if (!Meta.bOverride) continue;
if (!bHasOverrides) { Result.Append(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
if (!bHasOverrides) { UMCPServer::Print(TEXT("\nOverridden Parameters:\n")); bHasOverrides = true; }
MCPUtils::FormatMaterialParameter(Info, Meta);
}
// Inherited (non-overridden) parameters.
@@ -49,8 +50,8 @@ public:
for (auto& [Info, Meta] : AllParams)
{
if (Meta.bOverride) continue;
if (!bHasInherited) { Result.Append(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
if (!bHasInherited) { UMCPServer::Print(TEXT("\nInherited Parameters (not overridden):\n")); bHasInherited = true; }
MCPUtils::FormatMaterialParameter(Info, Meta);
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -40,7 +41,7 @@ public:
return TEXT("Set a parameter override on a Material Instance.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UMaterialInstanceConstant* MI = F.Asset(Path).Cast<UMaterialInstanceConstant>();
@@ -59,13 +60,13 @@ public:
FMaterialParameterMetadata* Found = AllParams.Find(ParamID);
if (!Found)
{
Result.Appendf(TEXT("No parameter named '%s' with association=%s layer=%d"),
UMCPServer::Printf(TEXT("No parameter named '%s' with association=%s layer=%d"),
*Parameter, *ParameterAssociation, ParameterLayer);
return;
}
if (Found->PrimitiveDataIndex != INDEX_NONE)
{
Result.Appendf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
UMCPServer::Printf(TEXT("Parameter '%s' uses custom primitive data and cannot be set on a material instance"), *Parameter);
return;
}
@@ -78,7 +79,7 @@ public:
float ScalarValue;
if (!FDefaultValueHelper::ParseFloat(Value, ScalarValue))
{
Result.Appendf(TEXT("Failed to parse '%s' as a float"), *Value);
UMCPServer::Printf(TEXT("Failed to parse '%s' as a float"), *Value);
return;
}
MI->SetScalarParameterValueEditorOnly(ParamID, ScalarValue);
@@ -89,19 +90,19 @@ public:
FLinearColor Color;
if (!Color.InitFromString(Value))
{
Result.Appendf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
UMCPServer::Printf(TEXT("Failed to parse '%s' as a color/vector (expected format: '(R=1,G=0,B=0,A=1)')"), *Value);
return;
}
MI->SetVectorParameterValueEditorOnly(ParamID, Color);
break;
}
default:
Result.Appendf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
UMCPServer::Printf(TEXT("Parameters of type %d (see EMaterialParameterType) are not implemented"), (int)Type);
return;
}
MCPUtils::SaveGenericPackage(MI);
Result.Appendf(TEXT("Set '%s' = %s on %s\n"),
UMCPServer::Printf(TEXT("Set '%s' = %s on %s\n"),
*Parameter, *Value, *MCPUtils::FormatName(MI));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -26,7 +27,7 @@ public:
return TEXT("Force recompile a material and check for compilation errors.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load material
MCPFetcher F;
@@ -47,14 +48,14 @@ public:
if (Errors.IsEmpty())
{
Result.Appendf(TEXT("%s compiled successfully.\n"), *MCPUtils::FormatName(MaterialObj));
UMCPServer::Printf(TEXT("%s compiled successfully.\n"), *MCPUtils::FormatName(MaterialObj));
}
else
{
Result.Appendf(TEXT("%s compiled with %d error(s):\n"), *MCPUtils::FormatName(MaterialObj), Errors.Num());
UMCPServer::Printf(TEXT("%s compiled with %d error(s):\n"), *MCPUtils::FormatName(MaterialObj), Errors.Num());
for (const FString& Err : Errors)
{
Result.Appendf(TEXT(" %s\n"), *Err);
UMCPServer::Printf(TEXT(" %s\n"), *Err);
}
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -38,7 +39,7 @@ public:
return TEXT("Create a new UMaterial asset with optional domain, blend mode, and two-sided settings.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -73,11 +74,11 @@ public:
bool bSaved = MCPUtils::SaveGenericPackage(MaterialObj);
Result.Appendf(TEXT("Created %s\n"), *MaterialObj->GetPathName());
Result.Appendf(TEXT("Domain: %s\n"), *MCPUtils::EnumToString(MaterialObj->MaterialDomain, TEXT("MD_")));
Result.Appendf(TEXT("BlendMode: %s\n"), *MCPUtils::EnumToString(MaterialObj->BlendMode, TEXT("BLEND_")));
Result.Appendf(TEXT("TwoSided: %s\n"), MaterialObj->TwoSided ? TEXT("true") : TEXT("false"));
UMCPServer::Printf(TEXT("Created %s\n"), *MaterialObj->GetPathName());
UMCPServer::Printf(TEXT("Domain: %s\n"), *MCPUtils::EnumToString(MaterialObj->MaterialDomain, TEXT("MD_")));
UMCPServer::Printf(TEXT("BlendMode: %s\n"), *MCPUtils::EnumToString(MaterialObj->BlendMode, TEXT("BLEND_")));
UMCPServer::Printf(TEXT("TwoSided: %s\n"), MaterialObj->TwoSided ? TEXT("true") : TEXT("false"));
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -27,7 +27,7 @@ public:
return TEXT("List all parameters on a Material, showing their default values.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UMaterial* Mat = F.Asset(Path).Cast<UMaterial>();
@@ -37,7 +37,7 @@ public:
for (auto& [Info, Meta] : AllParams)
{
MCPUtils::FormatMaterialParameter(Result, Info, Meta);
MCPUtils::FormatMaterialParameter(Info, Meta);
}
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPProperty.h"
@@ -36,7 +37,7 @@ public:
"showing current values and which properties are editable.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Resolve the path to an object and get its editable template.
MCPFetcher F;
@@ -70,9 +71,9 @@ public:
for (const FString& Category : Categories)
{
if (Category.IsEmpty())
Result.Append(TEXT("\nUncategorized:\n"));
UMCPServer::Print(TEXT("\nUncategorized:\n"));
else
Result.Appendf(TEXT("\n%s:\n"), *Category);
UMCPServer::Printf(TEXT("\n%s:\n"), *Category);
for (MCPProperty& P : ByCategory[Category])
{
@@ -83,7 +84,7 @@ public:
ValueStr = ValueStr.Left(80) + TEXT("...");
bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst);
Result.Appendf(TEXT(" %s %s %s = %s\n"),
UMCPServer::Printf(TEXT(" %s %s %s = %s\n"),
bEditable ? TEXT("editable") : TEXT("readonly"),
*MCPUtils::FormatPropertyType(P.Prop),
*PropName,
@@ -92,6 +93,6 @@ public:
}
if (Props.IsEmpty())
Result.Append(TEXT(" (no blueprint-visible properties found)\n"));
UMCPServer::Print(TEXT(" (no blueprint-visible properties found)\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPProperty.h"
@@ -29,7 +30,7 @@ public:
return TEXT("Get the value of a single property on an object resolved via MCPFetcher path.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPFetcher F;
UObject* Template = F.Walk(Path).Template().Cast<UObject>();
@@ -38,7 +39,7 @@ public:
MCPProperty P = MCPProperty::GetOneExactMatch(Template, CPF_Edit, Property);
if (!P) return;
Result.Append(P.GetText());
Result.Append(TEXT("\n"));
UMCPServer::Print(P.GetText());
UMCPServer::Print(TEXT("\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPProperty.h"
@@ -30,7 +31,7 @@ public:
"Properties is a JSON object like {\"TwoSided\": \"true\", \"BlendMode\": \"BLEND_Translucent\"}.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Resolve the path to an object and get its editable template.
MCPFetcher F;
@@ -39,7 +40,7 @@ public:
if (!Properties.Json || Properties.Json->Values.Num() == 0)
{
Result.Append(TEXT("Error: No properties specified\n"));
UMCPServer::Print(TEXT("Error: No properties specified\n"));
return;
}
@@ -53,7 +54,7 @@ public:
FString ValueStr;
if (!Pair.Value->TryGetString(ValueStr))
{
Result.Appendf(TEXT("Error: Value for '%s' must be a string\n"), *Pair.Key);
UMCPServer::Printf(TEXT("Error: Value for '%s' must be a string\n"), *Pair.Key);
return;
}
Resolved.Emplace(P, ValueStr);
@@ -71,8 +72,8 @@ public:
// Save.
bool bSaved = MCPUtils::SaveGenericPackage(Template);
Result.Appendf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
UMCPServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
if (!bSaved)
Result.Append(TEXT("Warning: Save failed\n"));
UMCPServer::Print(TEXT("Warning: Save failed\n"));
}
};

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPServer.h"
#include "MCPUtils.h"
#include "ShowCommands.generated.h"
@@ -23,7 +24,7 @@ public:
return TEXT("List all available commands with their descriptions.");
}
virtual void Handle(FStringBuilderBase& Result) override
void EmitCommandList()
{
FString QueryLower = Query.ToLower();
FString PrevGroup;
@@ -39,40 +40,47 @@ public:
if (Group != PrevGroup)
{
if (!PrevGroup.IsEmpty())
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
PrevGroup = Group;
}
if (Verbose)
{
MCPUtils::FormatCommandHelp(Class, Result);
MCPUtils::FormatCommandHelp(Class);
continue;
}
Result.Append(ToolName);
Result.Append(TEXT("("));
UMCPServer::Print(ToolName);
UMCPServer::Print(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(Class, EFieldIterationFlags::None); PropIt; ++PropIt)
{
if (!bFirst) Result.Append(TEXT(","));
if (!bFirst) UMCPServer::Print(TEXT(","));
bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) Result.Append(TEXT("?"));
Result.Append(MCPUtils::FormatPropertyType(*PropIt));
Result.Append(TEXT(" "));
Result.Append(MCPUtils::PropertyNameToJsonKey(PropIt->GetName()));
if (PropIt->HasMetaData(TEXT("Optional"))) UMCPServer::Print(TEXT("?"));
UMCPServer::Print(MCPUtils::FormatPropertyType(*PropIt));
UMCPServer::Print(TEXT(" "));
UMCPServer::Print(MCPUtils::PropertyNameToJsonKey(PropIt->GetName()));
}
Result.Append(TEXT(")\n"));
UMCPServer::Print(TEXT(")\n"));
}
}
virtual void Handle() override
{
UMCPServer::Printf(TEXT("\n"));
EmitCommandList();
// Append Path documentation.
Result.Append(TEXT("\n"));
Result.Append(TEXT("Some commands take a Path parameter. A Path starts with an asset\n"));
Result.Append(TEXT("package path (e.g. /Game/Widgets/WB_Hotkeys), followed by zero or\n"));
Result.Append(TEXT("more comma-separated steps that navigate into the asset:\n"));
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
UMCPServer::Print(TEXT("Some commands take a Path parameter. A Path starts with an asset\n"));
UMCPServer::Print(TEXT("package path (e.g. /Game/Widgets/WB_Hotkeys), followed by zero or\n"));
UMCPServer::Print(TEXT("more comma-separated steps that navigate into the asset:\n"));
UMCPServer::Print(TEXT("\n"));
for (const MCPFetcher::FWalker& W : MCPFetcher::GetWalkerTable())
{
Result.Appendf(TEXT(" %s — %s\n"), W.Key, W.Description);
UMCPServer::Printf(TEXT(" %s — %s\n"), W.Key, W.Description);
}
Result.Append(TEXT("\nExample: /Game/Widgets/WB_Hotkeys,graph:EventGraph,node:Self_Reference_03,pin:Result\n"));
UMCPServer::Print(TEXT("\nExample: /Game/Widgets/WB_Hotkeys,graph:EventGraph,node:Self_Reference_03,pin:Result\n"));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPFetcher.h"
@@ -49,7 +50,7 @@ public:
"Optionally assign an animation asset to the state.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Resolve the anim blueprint
MCPFetcher F;
@@ -60,14 +61,14 @@ public:
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(AnimBP, Graph);
if (!SMGraph)
{
Result.Appendf(TEXT("ERROR: State machine graph '%s' not found in %s\n"), *Graph, *MCPUtils::FormatName(AnimBP));
UMCPServer::Printf(TEXT("ERROR: State machine graph '%s' not found in %s\n"), *Graph, *MCPUtils::FormatName(AnimBP));
return;
}
// Check for duplicate state name
if (MCPUtils::FindStateByName(SMGraph, StateName))
{
Result.Appendf(TEXT("ERROR: State '%s' already exists in %s\n"), *StateName, *MCPUtils::FormatName(SMGraph));
UMCPServer::Printf(TEXT("ERROR: State '%s' already exists in %s\n"), *StateName, *MCPUtils::FormatName(SMGraph));
return;
}
@@ -110,7 +111,7 @@ public:
FKismetEditorUtilities::CompileBlueprint(AnimBP);
MCPUtils::SaveBlueprintPackage(AnimBP);
Result.Appendf(TEXT("Created state '%s' in %s\n"), *StateName, *MCPUtils::FormatName(SMGraph));
Result.Appendf(TEXT(" node: %s\n"), *MCPUtils::FormatName(NewState));
UMCPServer::Printf(TEXT("Created state '%s' in %s\n"), *StateName, *MCPUtils::FormatName(SMGraph));
UMCPServer::Printf(TEXT(" node: %s\n"), *MCPUtils::FormatName(NewState));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -48,7 +49,7 @@ public:
return TEXT("Add a transition between two states in an animation state machine graph.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UAnimBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -57,7 +58,7 @@ public:
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(AnimBP, Graph);
if (!SMGraph)
{
Result.Appendf(TEXT("ERROR: State machine graph '%s' not found in '%s'\n"), *Graph, *MCPUtils::FormatName(AnimBP));
UMCPServer::Printf(TEXT("ERROR: State machine graph '%s' not found in '%s'\n"), *Graph, *MCPUtils::FormatName(AnimBP));
return;
}
@@ -92,7 +93,7 @@ public:
FKismetEditorUtilities::CompileBlueprint(AnimBP);
MCPUtils::SaveBlueprintPackage(AnimBP);
Result.Appendf(TEXT("Created transition %s -> %s: %s\n"),
UMCPServer::Printf(TEXT("Created transition %s -> %s: %s\n"),
*FromState, *ToState, *MCPUtils::FormatName(TransNode));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
@@ -33,7 +34,7 @@ public:
return TEXT("Remove a state and its connected transitions from an animation state machine graph.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Fetch the state machine graph via MCPFetcher
MCPFetcher F;
@@ -47,7 +48,7 @@ public:
UBlueprint* BP = Cast<UBlueprint>(SMGraph->GetOuter()->GetOuter());
if (!BP)
{
Result.Append(TEXT("ERROR: Could not find owning blueprint.\n"));
UMCPServer::Print(TEXT("ERROR: Could not find owning blueprint.\n"));
return;
}
@@ -75,7 +76,7 @@ public:
FKismetEditorUtilities::CompileBlueprint(BP);
MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("Removed state %s and %d transition(s).\n"),
UMCPServer::Printf(TEXT("Removed state %s and %d transition(s).\n"),
*MCPUtils::FormatName(StateNode), RemovedTransitions);
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPFetcher.h"
@@ -43,7 +44,7 @@ public:
return TEXT("Set or replace the animation sequence played by a state in an animation state machine.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Resolve the anim blueprint
MCPFetcher F;
@@ -54,7 +55,7 @@ public:
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(AnimBP, Graph);
if (!SMGraph)
{
Result.Appendf(TEXT("ERROR: State machine graph '%s' not found in %s\n"), *Graph, *MCPUtils::FormatName(AnimBP));
UMCPServer::Printf(TEXT("ERROR: State machine graph '%s' not found in %s\n"), *Graph, *MCPUtils::FormatName(AnimBP));
return;
}
@@ -65,7 +66,7 @@ public:
UEdGraph* InnerGraph = StateNode->GetBoundGraph();
if (!InnerGraph)
{
Result.Appendf(TEXT("ERROR: State '%s' has no bound graph\n"), *StateName);
UMCPServer::Printf(TEXT("ERROR: State '%s' has no bound graph\n"), *StateName);
return;
}
@@ -102,8 +103,8 @@ public:
MCPUtils::SaveBlueprintPackage(AnimBP);
if (bCreatedNew)
Result.Appendf(TEXT("Created sequence player in state '%s', assigned %s\n"), *StateName, *MCPUtils::FormatName(AnimSeq));
UMCPServer::Printf(TEXT("Created sequence player in state '%s', assigned %s\n"), *StateName, *MCPUtils::FormatName(AnimSeq));
else
Result.Appendf(TEXT("Updated sequence player in state '%s' to %s\n"), *StateName, *MCPUtils::FormatName(AnimSeq));
UMCPServer::Printf(TEXT("Updated sequence player in state '%s' to %s\n"), *StateName, *MCPUtils::FormatName(AnimSeq));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPFetcher.h"
@@ -53,7 +54,7 @@ public:
"and optionally wire blueprint variables to the X and Y axis inputs.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
// Load the anim blueprint
MCPAssets<UAnimBlueprint> Assets;
@@ -62,13 +63,13 @@ public:
// Find the state machine graph and state
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(AnimBP, Graph);
if (!SMGraph) { Result.Appendf(TEXT("ERROR: State machine graph '%s' not found\n"), *Graph); return; }
if (!SMGraph) { UMCPServer::Printf(TEXT("ERROR: State machine graph '%s' not found\n"), *Graph); return; }
UAnimStateNode* StateNode = MCPUtils::FindStateByName(SMGraph, StateName);
if (!StateNode) return;
UEdGraph* InnerGraph = StateNode->GetBoundGraph();
if (!InnerGraph) { Result.Appendf(TEXT("ERROR: State '%s' has no bound graph\n"), *StateName); return; }
if (!InnerGraph) { UMCPServer::Printf(TEXT("ERROR: State '%s' has no bound graph\n"), *StateName); return; }
// Load the blend space asset
MCPAssets<UBlendSpace> BlendSpaceAssets;
@@ -100,17 +101,17 @@ public:
ConnectToOutputPose(BSNode, InnerGraph);
// Wire X and Y variables if provided
WireVariable(AnimBP, InnerGraph, BSNode, XVariable, TEXT("X"), Result);
WireVariable(AnimBP, InnerGraph, BSNode, YVariable, TEXT("Y"), Result);
WireVariable(AnimBP, InnerGraph, BSNode, XVariable, TEXT("X"));
WireVariable(AnimBP, InnerGraph, BSNode, YVariable, TEXT("Y"));
// Compile and save
FKismetEditorUtilities::CompileBlueprint(AnimBP);
bool bSaved = MCPUtils::SaveBlueprintPackage(AnimBP);
Result.Appendf(TEXT("BlendSpacePlayer %s placed in state %s\n"),
UMCPServer::Printf(TEXT("BlendSpacePlayer %s placed in state %s\n"),
*MCPUtils::FormatName(BSNode), *StateName);
if (!bSaved)
Result.Append(TEXT("WARNING: Failed to save package\n"));
UMCPServer::Print(TEXT("WARNING: Failed to save package\n"));
}
private:
@@ -160,7 +161,7 @@ private:
void WireVariable(UAnimBlueprint* AnimBP, UEdGraph* InnerGraph,
UAnimGraphNode_BlendSpacePlayer* BSNode, const FString& VarName,
const TCHAR* PinName, FStringBuilderBase& Result)
const TCHAR* PinName)
{
if (VarName.IsEmpty()) return;
@@ -185,7 +186,7 @@ private:
}
if (!bVarFound)
{
Result.Appendf(TEXT("WARNING: Variable '%s' not found, skipping %s wire\n"), *VarName, PinName);
UMCPServer::Printf(TEXT("WARNING: Variable '%s' not found, skipping %s wire\n"), *VarName, PinName);
return;
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -53,7 +54,7 @@ public:
return TEXT("Update properties on an existing transition between two states in an animation state machine.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPAssets<UAnimBlueprint> Assets;
if (!Assets.Exact(Blueprint).ENone().ETwo().Load()) return;
@@ -62,14 +63,14 @@ public:
UAnimationStateMachineGraph* SMGraph = MCPUtils::FindStateMachineGraph(AnimBP, Graph);
if (!SMGraph)
{
Result.Appendf(TEXT("ERROR: State machine graph '%s' not found in '%s'\n"), *Graph, *MCPUtils::FormatName(AnimBP));
UMCPServer::Printf(TEXT("ERROR: State machine graph '%s' not found in '%s'\n"), *Graph, *MCPUtils::FormatName(AnimBP));
return;
}
UAnimStateTransitionNode* TransNode = MCPUtils::FindTransition(SMGraph, FromState, ToState);
if (!TransNode)
{
Result.Appendf(TEXT("ERROR: Transition from '%s' to '%s' not found in graph '%s'\n"),
UMCPServer::Printf(TEXT("ERROR: Transition from '%s' to '%s' not found in graph '%s'\n"),
*FromState, *ToState, *Graph);
return;
}
@@ -85,7 +86,7 @@ public:
FKismetEditorUtilities::CompileBlueprint(AnimBP);
MCPUtils::SaveBlueprintPackage(AnimBP);
Result.Appendf(TEXT("Updated transition %s -> %s: %s\n"),
UMCPServer::Printf(TEXT("Updated transition %s -> %s: %s\n"),
*FromState, *ToState, *MCPUtils::FormatName(TransNode));
}
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPServer.h"
#include "MCPHandler.h"
#include "MCPAssets.h"
#include "MCPUtils.h"
@@ -45,7 +46,7 @@ public:
return TEXT("Create a new UserDefinedStruct asset with optional initial properties.");
}
virtual void Handle(FStringBuilderBase& Result) override
virtual void Handle() override
{
MCPPackageMaker Maker(AssetPath);
if (!Maker.Ok()) return;
@@ -88,10 +89,10 @@ public:
bool bSaved = MCPUtils::SaveGenericPackage(NewStruct);
Result.Appendf(TEXT("Created %s\n"), *NewStruct->GetPathName());
UMCPServer::Printf(TEXT("Created %s\n"), *NewStruct->GetPathName());
if (PropsAdded > 0)
Result.Appendf(TEXT("Properties added: %d\n"), PropsAdded);
UMCPServer::Printf(TEXT("Properties added: %d\n"), PropsAdded);
if (!bSaved)
Result.Append(TEXT("WARNING: Package save failed\n"));
UMCPServer::Print(TEXT("WARNING: Package save failed\n"));
}
};

View File

@@ -260,57 +260,17 @@ TStatId UMCPServer::GetStatId() const
FString UMCPServer::HandleRequest(const FString& Line)
{
// Turn the request string into a JSON tree.
TSharedPtr<FJsonObject> Request;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Line);
FJsonSerializer::Deserialize(Reader, Request);
if (!Request.IsValid())
{
return TEXT("Request is not valid JSON");
}
// Extract the command from the request.
FString Command;
if (!Request->TryGetStringField(TEXT("command"), Command))
{
return TEXT("Request does not contain 'command' parameter");
}
Request->RemoveField(TEXT("command"));
// Find the handler UClass for the specified command.
UClass** HandlerClass = MCPHandlerRegistry.Find(Command);
if (!HandlerClass)
{
return FString::Printf(TEXT("Unknown command: %s"), *Command);
}
// Make an object of the handler class.
TStrongObjectPtr<UObject> HandlerObj(NewObject<UObject>(GetTransientPackage(), *HandlerClass));
IMCPHandler* Handler = Cast<IMCPHandler>(HandlerObj.Get());
// Populate the handler object with the request parameters.
HandlerOutput.Reset();
if (!MCPUtils::PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), &*Request))
{
HandlerOutput.Append(TEXT("\nUsage:\n"));
MCPUtils::FormatCommandHelp(*HandlerClass, HandlerOutput);
FString Result = HandlerOutput.ToString();
HandlerOutput.Reset();
return Result;
}
// Invoke the handler with log capture.
LogCapture.CapturedErrors.Empty();
LogCapture.bEnabled = true;
HandlerOutput.Reset();
Handler->Handle(HandlerOutput);
TryCallHandler(Line);
Notifier.SendNotifications();
LogCapture.bEnabled = false;
for (const FString& Msg : LogCapture.CapturedErrors)
{
HandlerOutput.Append(TEXT("LOG: "));
HandlerOutput.Append(Msg);
HandlerOutput.Append(TEXT("\n"));
UMCPServer::Printf(TEXT("UE_LOG: %s\n"), *Msg);
}
LogCapture.CapturedErrors.Empty();
FString Result = HandlerOutput.ToString();
@@ -322,6 +282,51 @@ FString UMCPServer::HandleRequest(const FString& Line)
return Result;
}
void UMCPServer::TryCallHandler(const FString &Line)
{
// Turn the request string into a JSON tree.
TSharedPtr<FJsonObject> Request;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(Line);
FJsonSerializer::Deserialize(Reader, Request);
if (!Request.IsValid())
{
UMCPServer::Printf(TEXT("Request is not valid JSON"));
return;
}
// Extract the command from the request.
FString Command;
if (!Request->TryGetStringField(TEXT("command"), Command))
{
UMCPServer::Printf(TEXT("Request does not contain 'command' parameter"));
return;
}
Request->RemoveField(TEXT("command"));
// Find the handler UClass for the specified command.
UClass** HandlerClass = MCPHandlerRegistry.Find(Command);
if (!HandlerClass)
{
UMCPServer::Printf(TEXT("Unknown command: %s"), *Command);
return;
}
// Make an object of the handler class.
TStrongObjectPtr<UObject> HandlerObj(NewObject<UObject>(GetTransientPackage(), *HandlerClass));
IMCPHandler* Handler = Cast<IMCPHandler>(HandlerObj.Get());
// Populate the handler object with the request parameters.
if (!MCPUtils::PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), &*Request))
{
UMCPServer::Printf(TEXT("\nUsage:\n\n"));
MCPUtils::FormatCommandHelp(*HandlerClass);
return;
}
// Invoke the handler.
Handler->Handle();
}
// ============================================================
// Connection Maintenance
// ============================================================

View File

@@ -813,7 +813,7 @@ bool MCPUtils::ParseMaterialParameterAssociation(const FString& Str, EMaterialPa
return true;
}
void MCPUtils::FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
void MCPUtils::FormatMaterialParameter(const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta)
{
// Association prefix for layer/blend parameters.
FString Prefix;
@@ -825,35 +825,35 @@ void MCPUtils::FormatMaterialParameter(FStringBuilderBase& Result, const FMateri
switch (Meta.Value.Type)
{
case EMaterialParameterType::Scalar:
Result.Appendf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar());
UMCPServer::Printf(TEXT(" %sScalar \"%s\" = %g\n"), *Prefix, *Info.Name.ToString(), Meta.Value.AsScalar());
break;
case EMaterialParameterType::Vector:
{
FLinearColor C = Meta.Value.AsLinearColor();
Result.Appendf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"),
UMCPServer::Printf(TEXT(" %sVector \"%s\" = (R=%.3f, G=%.3f, B=%.3f, A=%.3f)\n"),
*Prefix, *Info.Name.ToString(), C.R, C.G, C.B, C.A);
break;
}
case EMaterialParameterType::DoubleVector:
{
FVector4d V = Meta.Value.AsVector4d();
Result.Appendf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
UMCPServer::Printf(TEXT(" %sDoubleVector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
*Prefix, *Info.Name.ToString(), V.X, V.Y, V.Z, V.W);
break;
}
case EMaterialParameterType::Texture:
{
UTexture* Tex = Cast<UTexture>(Meta.Value.AsTextureObject());
Result.Appendf(TEXT(" %sTexture \"%s\" = %s\n"),
UMCPServer::Printf(TEXT(" %sTexture \"%s\" = %s\n"),
*Prefix, *Info.Name.ToString(), Tex ? *MCPUtils::FormatName(Tex) : TEXT("None"));
break;
}
case EMaterialParameterType::StaticSwitch:
Result.Appendf(TEXT(" %sStaticSwitch \"%s\" = %s\n"),
UMCPServer::Printf(TEXT(" %sStaticSwitch \"%s\" = %s\n"),
*Prefix, *Info.Name.ToString(), Meta.Value.AsStaticSwitch() ? TEXT("true") : TEXT("false"));
break;
default:
Result.Appendf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString());
UMCPServer::Printf(TEXT(" %sType%d \"%s\"\n"), *Prefix, (int)Meta.Value.Type, *Info.Name.ToString());
break;
}
}
@@ -1398,29 +1398,29 @@ TArray<FProperty*> MCPUtils::SearchProperties(UObject* Obj, const FString& Query
// FormatCommandHelp — verbose description of one handler command
// ============================================================
void MCPUtils::FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Result)
void MCPUtils::FormatCommandHelp(UClass* HandlerClass)
{
const IMCPHandler* Handler = Cast<IMCPHandler>(HandlerClass->GetDefaultObject());
if (!Handler) return;
FString ToolName = GetHandlerName(HandlerClass);
Result.Append(TEXT("\n"));
Result.Append(WrapText(Handler->GetDescription(), 80, TEXT("// ")));
Result.Append(TEXT("\n"));
UMCPServer::Print(TEXT("\n"));
UMCPServer::Print(WrapText(Handler->GetDescription(), 80, TEXT("// ")));
UMCPServer::Print(TEXT("\n"));
// Command signature line
Result.Append(ToolName);
Result.Append(TEXT("("));
UMCPServer::Print(ToolName);
UMCPServer::Print(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(HandlerClass, EFieldIterationFlags::None); PropIt; ++PropIt)
{
if (!bFirst) Result.Append(TEXT(","));
if (!bFirst) UMCPServer::Print(TEXT(","));
bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) Result.Append(TEXT("?"));
Result.Append(PropertyNameToJsonKey(PropIt->GetName()));
if (PropIt->HasMetaData(TEXT("Optional"))) UMCPServer::Print(TEXT("?"));
UMCPServer::Print(PropertyNameToJsonKey(PropIt->GetName()));
}
Result.Append(TEXT(")\n"));
UMCPServer::Print(TEXT(")\n"));
// parameter details
for (TFieldIterator<FProperty> PropIt(HandlerClass, EFieldIterationFlags::None); PropIt; ++PropIt)
@@ -1431,10 +1431,10 @@ void MCPUtils::FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Resul
bool bOptional = Prop->HasMetaData(TEXT("Optional"));
const FString& Desc = Prop->GetMetaData(TEXT("Description"));
Result.Appendf(TEXT(" %s %s%s"),
UMCPServer::Printf(TEXT(" %s %s%s"),
*Type, *Name, bOptional ? TEXT(" (optional)") : TEXT(""));
if (!Desc.IsEmpty())
Result.Appendf(TEXT(" — %s"), *Desc);
Result.Append(TEXT("\n"));
UMCPServer::Printf(TEXT(" — %s"), *Desc);
UMCPServer::Print(TEXT("\n"));
}
}

View File

@@ -51,5 +51,5 @@ public:
virtual FString GetDescription() const = 0;
// Called after parameter fields have been populated from JSON.
virtual void Handle(FStringBuilderBase& Result) {}
virtual void Handle() {}
};

View File

@@ -53,6 +53,7 @@ public:
/** Print text to the handler output buffer. */
static void Print(const TCHAR* Text) { GMCPServer->HandlerOutput.Append(Text); }
static void Print(const FString& Text) { GMCPServer->HandlerOutput.Append(Text); }
/** Print formatted text to the handler output buffer. */
template <typename FmtType, typename... ArgTypes>
@@ -79,6 +80,7 @@ private:
// Handle a complete JSON line and return the response JSON
FString HandleRequest(const FString& Line);
void TryCallHandler(const FString &Line);
// ----- TCP server -----
FSocket* ListenSocket = nullptr;

View File

@@ -162,7 +162,7 @@ public:
// ----- Material Parameters -----
static TMap<FMaterialParameterInfo, FMaterialParameterMetadata> GetMaterialParameters(UMaterialInterface* Material);
static bool ParseMaterialParameterAssociation(const FString& Str, EMaterialParameterAssociation& OutAssociation);
static void FormatMaterialParameter(FStringBuilderBase& Result, const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta);
static void FormatMaterialParameter(const FMaterialParameterInfo& Info, const FMaterialParameterMetadata& Meta);
// ----- Editable template -----
static TArray<FProperty*> SearchProperties(UObject* Obj, const FString& Query, EPropertyFlags Flags, bool bLocal);
@@ -183,7 +183,7 @@ public:
static TArray<UClass*> CollectHandlerClasses();
static FString GetHandlerName(UClass* HandlerClass);
static FString GetHandlerGroup(UClass* HandlerClass);
static void FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Result);
static void FormatCommandHelp(UClass* HandlerClass);
private: