Broad rearrangement of handlers

This commit is contained in:
2026-03-12 00:44:17 -04:00
parent 2e058035f3
commit d69fc4cd1e
98 changed files with 270 additions and 1032 deletions

View File

@@ -9,15 +9,15 @@
#include "Animation/AnimInstance.h"
#include "Animation/Skeleton.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "UMCPHandler_CreateAnimBlueprintAsset.generated.h"
#include "AnimBlueprint_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateAnimBlueprintAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_AnimBlueprint_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Animation/AnimBlueprint.h"
#include "AnimGraphNode_Base.h"
#include "UMCPHandler_ListAnimSlotNames.generated.h"
#include "AnimBlueprint_ListSlotNames.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListAnimSlotNames : public UObject, public IMCPHandler
UCLASS()
class UMCP_AnimBlueprint_ListSlotNames : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Animation/AnimBlueprint.h"
#include "AnimGraphNode_Base.h"
#include "UMCPHandler_ListAnimSyncGroups.generated.h"
#include "AnimBlueprint_ListSyncGroups.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListAnimSyncGroups : public UObject, public IMCPHandler
UCLASS()
class UMCP_AnimBlueprint_ListSyncGroups : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,7 +7,7 @@
#include "MCPUtils.h"
#include "Animation/AnimSequence.h"
#include "Animation/BlendSpace.h"
#include "UMCPHandler_SetBlendSpaceSamplePoints.generated.h"
#include "AnimBlueprint_SetBlendSpaceSamples.generated.h"
// ---------------------------------------------------------------------------
@@ -29,8 +29,8 @@ struct FBlendSpaceSampleEntry
float Y = 0.0f;
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetBlendSpaceSamplePoints : public UObject, public IMCPHandler
UCLASS()
class UMCP_AnimBlueprint_SetBlendSpaceSamples : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "Misc/Paths.h"
#include "Misc/PackageName.h"
#include "HAL/FileManager.h"
#include "UMCPHandler_BackupAsset.generated.h"
#include "Asset_Backup.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_BackupAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Asset_Backup : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -8,15 +8,15 @@
#include "AssetRegistry/AssetRegistryModule.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "HAL/FileManager.h"
#include "UMCPHandler_DeleteAsset.generated.h"
#include "Asset_Delete.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Asset_Delete : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,15 +4,15 @@
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "UMCPHandler_FindAssetReferences.generated.h"
#include "Asset_FindReferences.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_FindAssetReferences : public UObject, public IMCPHandler
UCLASS()
class UMCP_Asset_FindReferences : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "UMCPHandler_RenameAsset.generated.h"
#include "Asset_Rename.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RenameAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Asset_Rename : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "Misc/PackageName.h"
#include "FileHelpers.h"
#include "HAL/FileManager.h"
#include "UMCPHandler_RestoreAsset.generated.h"
#include "Asset_Restore.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RestoreAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Asset_Restore : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,15 +4,15 @@
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "UMCPHandler_SearchAssets.generated.h"
#include "Asset_Search.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchAssets : public UObject, public IMCPHandler
UCLASS()
class UMCP_Asset_Search : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Animation/Skeleton.h"
#include "Animation/BlendSpace.h"
#include "UMCPHandler_CreateBlendSpaceAsset.generated.h"
#include "BlendSpace_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateBlendSpaceAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_BlendSpace_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -10,15 +10,15 @@
#include "EdGraphSchema_K2.h"
#include "K2Node_CustomEvent.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_CreateBlueprintGraph.generated.h"
#include "BlueprintGraph_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateBlueprintGraph : public UObject, public IMCPHandler
UCLASS()
class UMCP_BlueprintGraph_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,15 +7,15 @@
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_DeleteBlueprintGraph.generated.h"
#include "BlueprintGraph_Delete.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteBlueprintGraph : public UObject, public IMCPHandler
UCLASS()
class UMCP_BlueprintGraph_Delete : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,15 +7,15 @@
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_RenameBlueprintGraph.generated.h"
#include "BlueprintGraph_Rename.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RenameBlueprintGraph : public UObject, public IMCPHandler
UCLASS()
class UMCP_BlueprintGraph_Rename : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "Engine/SCS_Node.h"
#include "Components/ActorComponent.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_AddBlueprintComponent.generated.h"
#include "Blueprint_AddComponent.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddBlueprintComponent : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_AddComponent : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -10,7 +10,7 @@
#include "K2Node_FunctionEntry.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_AddEventDispatcher.generated.h"
#include "Blueprint_AddEventDispatcher.generated.h"
// ---------------------------------------------------------------------------
@@ -29,8 +29,8 @@ struct FDispatcherParamEntry
FString Type;
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddEventDispatcher : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_AddEventDispatcher : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -11,15 +11,15 @@
#include "K2Node_CustomEvent.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_AddFunctionParameter.generated.h"
#include "Blueprint_AddFunctionParameter.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddFunctionParameter : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_AddFunctionParameter : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,15 +7,15 @@
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UObject/UObjectIterator.h"
#include "UMCPHandler_AddBlueprintInterface.generated.h"
#include "Blueprint_AddInterface.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddBlueprintInterface : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_AddInterface : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_AddBlueprintVariable.generated.h"
#include "Blueprint_AddVariable.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddBlueprintVariable : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_AddVariable : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -11,15 +11,15 @@
#include "K2Node_CustomEvent.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_ChangeFunctionParameterType.generated.h"
#include "Blueprint_ChangeFunctionParameterType.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ChangeFunctionParameterType : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_ChangeFunctionParameterType : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -10,15 +10,15 @@
#include "K2Node_VariableGet.h"
#include "K2Node_VariableSet.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_ChangeBlueprintVariableType.generated.h"
#include "Blueprint_ChangeVariableType.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ChangeBlueprintVariableType : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_ChangeVariableType : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "UMCPHandler_CompileBlueprint.generated.h"
#include "Blueprint_Compile.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CompileBlueprint : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_Compile : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "UMCPHandler_CreateBlueprintAsset.generated.h"
#include "Blueprint_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateBlueprintAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -8,15 +8,15 @@
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "UMCPHandler_DiffTwoBlueprints.generated.h"
#include "Blueprint_Diff.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DiffTwoBlueprints : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_Diff : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "Animation/Skeleton.h"
#include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h"
#include "UMCPHandler_DumpBlueprint.generated.h"
#include "Blueprint_Dump.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpBlueprint : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_Dump : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,15 +7,15 @@
#include "Engine/Blueprint.h"
#include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h"
#include "UMCPHandler_ListBlueprintComponents.generated.h"
#include "Blueprint_ListComponents.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListBlueprintComponents : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_ListComponents : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -10,15 +10,15 @@
#include "K2Node_FunctionEntry.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_ListEventDispatchers.generated.h"
#include "Blueprint_ListEventDispatchers.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListEventDispatchers : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_ListEventDispatchers : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -5,15 +5,15 @@
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "UMCPHandler_ListBlueprintInterfaces.generated.h"
#include "Blueprint_ListInterfaces.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListBlueprintInterfaces : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_ListInterfaces : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_RefreshAllNodesInGraph.generated.h"
#include "Blueprint_RefreshAllNodes.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RefreshAllNodesInGraph : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_RefreshAllNodes : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -8,15 +8,15 @@
#include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_RemoveBlueprintComponent.generated.h"
#include "Blueprint_RemoveComponent.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveBlueprintComponent : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_RemoveComponent : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "K2Node_CustomEvent.h"
#include "K2Node_EditablePinBase.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_RemoveFunctionParameter.generated.h"
#include "Blueprint_RemoveFunctionParameter.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveFunctionParameter : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_RemoveFunctionParameter : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_RemoveBlueprintInterface.generated.h"
#include "Blueprint_RemoveInterface.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveBlueprintInterface : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_RemoveInterface : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_RemoveBlueprintVariable.generated.h"
#include "Blueprint_RemoveVariable.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveBlueprintVariable : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_RemoveVariable : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -8,15 +8,15 @@
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "UMCPHandler_ReparentBlueprint.generated.h"
#include "Blueprint_Reparent.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ReparentBlueprint : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_Reparent : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Engine/World.h"
#include "UMCPHandler_ListBlueprintAssets.generated.h"
#include "Blueprint_Search.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListBlueprintAssets : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_Search : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -14,15 +14,15 @@
#include "K2Node_CustomEvent.h"
#include "K2Node_VariableGet.h"
#include "K2Node_VariableSet.h"
#include "UMCPHandler_SearchWithinBlueprints.generated.h"
#include "Blueprint_SearchContents.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchWithinBlueprints : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_SearchContents : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_SetBlueprintVariableMetadata.generated.h"
#include "Blueprint_SetVariableMetadata.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetBlueprintVariableMetadata : public UObject, public IMCPHandler
UCLASS()
class UMCP_Blueprint_SetVariableMetadata : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,7 +4,7 @@
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "UObject/UObjectIterator.h"
#include "UMCPHandler_SearchUnrealClasses.generated.h"
#include "Class_Search.generated.h"
// ---------------------------------------------------------------------------
@@ -15,8 +15,8 @@
// HandleListClasses — discover available UClasses
// ============================================================
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchUnrealClasses : public UObject, public IMCPHandler
UCLASS()
class UMCP_Class_Search : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -3,15 +3,15 @@
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPUtils.h"
#include "UMCPHandler_ListClassProperties.generated.h"
#include "Class_ShowProperties.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListClassProperties : public UObject, public IMCPHandler
UCLASS()
class UMCP_Class_ShowProperties : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -3,15 +3,15 @@
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "Subsystems/AssetEditorSubsystem.h"
#include "UMCPHandler_ListOpenAssetEditors.generated.h"
#include "Editor_ListOpenAssets.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListOpenAssetEditors : public UObject, public IMCPHandler
UCLASS()
class UMCP_Editor_ListOpenAssets : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,15 +4,15 @@
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "Subsystems/AssetEditorSubsystem.h"
#include "UMCPHandler_OpenAssetEditor.generated.h"
#include "Editor_OpenAsset.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_OpenAssetEditor : public UObject, public IMCPHandler
UCLASS()
class UMCP_Editor_OpenAsset : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "Factories/EnumFactory.h"
#include "UMCPHandler_CreateEnumAsset.generated.h"
#include "Enum_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateEnumAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Enum_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,7 +9,7 @@
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphSchema.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_SpawnNodes.generated.h"
#include "GraphNode_Create.generated.h"
// ---------------------------------------------------------------------------
@@ -32,8 +32,8 @@ struct FSpawnNodeEntry
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SpawnNodes : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -41,14 +41,14 @@ public:
UPROPERTY(meta=(Description="Path to a graph, e.g. /Game/Foo,graph:EventGraph"))
FString Graph;
UPROPERTY(meta=(Description="Array of {actionName, posX, posY} objects. Use SearchSpawnableNodeTypes to find action names."))
UPROPERTY(meta=(Description="Array of {actionName, posX, posY} objects. Use GraphNodeSearchTypes to find action names."))
FMCPJsonArray Nodes;
virtual FString GetDescription() const override
{
return TEXT("Create nodes in any graph (Blueprint, Material, etc.) using the editor's action database. "
"Can create ANY node type that appears in the editor's right-click menu. "
"Use SearchSpawnableNodeTypes first to find the exact action name.");
"Use GraphNodeSearchTypes first to find the exact action name.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
@@ -70,7 +70,7 @@ 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 SearchSpawnableNodeTypes to find available actions.\n"),
Result.Appendf(TEXT("ERROR: No action found matching '%s'. Use GraphNodeSearchTypes to find available actions.\n"),
*Entry.ActionName);
continue;
}

View File

@@ -9,15 +9,15 @@
#include "K2Node_CustomEvent.h"
#include "K2Node_FunctionEntry.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_DeleteNodeFromGraph.generated.h"
#include "GraphNode_Delete.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteNodeFromGraph : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_Delete : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_DuplicateNodesInGraph.generated.h"
#include "GraphNode_Duplicate.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DuplicateNodesInGraph : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_Duplicate : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -5,15 +5,15 @@
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "EdGraph/EdGraphNode.h"
#include "UMCPHandler_GetNodeComment.generated.h"
#include "GraphNode_GetComment.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_GetNodeComment : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_GetComment : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphSchema.h"
#include "UMCPHandler_SearchSpawnableNodeTypes.generated.h"
#include "GraphNode_SearchTypes.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchSpawnableNodeTypes : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_SearchTypes : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -32,7 +32,7 @@ public:
{
return TEXT("Search the action database for node types that can be spawned in a graph. "
"Works with any graph type (Blueprint, Material, etc.). "
"Returns full action names for use with SpawnNodesInGraph.");
"Returns full action names for use with GraphNodeCreate.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "EdGraph/EdGraphNode.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_SetNodeComment.generated.h"
#include "GraphNode_SetComment.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetNodeComment : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_SetComment : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,7 +7,7 @@
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraphNode.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_SetNodePositions.generated.h"
#include "GraphNode_SetPositions.generated.h"
// ---------------------------------------------------------------------------
@@ -30,8 +30,8 @@ struct FMoveNodeEntry
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetNodePositions : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphNode_SetPositions : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,7 +6,7 @@
#include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_ConnectPins.generated.h"
#include "GraphPin_Connect.generated.h"
// ---------------------------------------------------------------------------
@@ -26,8 +26,8 @@ struct FConnectPinsEntry
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ConnectPins : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphPin_Connect : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,7 +6,7 @@
#include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_DisconnectPins.generated.h"
#include "GraphPin_Disconnect.generated.h"
// ---------------------------------------------------------------------------
@@ -26,8 +26,8 @@ struct FDisconnectPinEntry
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DisconnectPins : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphPin_Disconnect : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -5,7 +5,7 @@
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h"
#include "UMCPHandler_GetPinDetails.generated.h"
#include "GraphPin_GetDetails.generated.h"
// ---------------------------------------------------------------------------
@@ -16,8 +16,8 @@
// HandleGetPinInfo — detailed information about a specific pin
// ============================================================
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_GetPinDetails : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphPin_GetDetails : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,7 +6,7 @@
#include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_SetPinDefaultValues.generated.h"
#include "GraphPin_SetDefault.generated.h"
// ---------------------------------------------------------------------------
@@ -26,8 +26,8 @@ struct FSetPinDefaultEntry
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetPinDefaultValues : public UObject, public IMCPHandler
UCLASS()
class UMCP_GraphPin_SetDefault : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "EdGraph/EdGraph.h"
#include "Materials/Material.h"
#include "MaterialGraph/MaterialGraph.h"
#include "UMCPHandler_DumpGraphs.generated.h"
#include "Graph_Dump.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpGraphs : public UObject, public IMCPHandler
UCLASS()
class UMCP_Graph_Dump : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -8,15 +8,15 @@
#include "Factories/MaterialFunctionFactoryNew.h"
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "UMCPHandler_CreateMaterialFunctionAsset.generated.h"
#include "MaterialFunction_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateMaterialFunctionAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_MaterialFunction_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -10,15 +10,15 @@
#include "Factories/MaterialInstanceConstantFactoryNew.h"
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "UMCPHandler_CreateMaterialInstanceAsset.generated.h"
#include "MaterialInstance_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateMaterialInstanceAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_MaterialInstance_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "MaterialDomain.h"
#include "UMCPHandler_CompileMaterial.generated.h"
#include "Material_Compile.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CompileMaterial : public UObject, public IMCPHandler
UCLASS()
class UMCP_Material_Compile : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "Factories/MaterialFactoryNew.h"
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "UMCPHandler_CreateMaterialAsset.generated.h"
#include "Material_Create.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateMaterialAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Material_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -12,15 +12,15 @@
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Engine/Texture.h"
#include "UMCPHandler_DumpMaterialInstanceParameters.generated.h"
#include "Material_DumpInstanceParameters.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpMaterialInstanceParameters : public UObject, public IMCPHandler
UCLASS()
class UMCP_Material_DumpInstanceParameters : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -7,15 +7,15 @@
#include "Materials/Material.h"
#include "Materials/MaterialInterface.h"
#include "Materials/MaterialInstanceConstant.h"
#include "UMCPHandler_ReparentMaterialInstance.generated.h"
#include "Material_ReparentInstance.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ReparentMaterialInstance : public UObject, public IMCPHandler
UCLASS()
class UMCP_Material_ReparentInstance : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -12,15 +12,15 @@
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Engine/Texture.h"
#include "UMCPHandler_SetMaterialInstanceParameter.generated.h"
#include "Material_SetInstanceParameter.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialInstanceParameter : public UObject, public IMCPHandler
UCLASS()
class UMCP_Material_SetInstanceParameter : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -6,15 +6,15 @@
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "MaterialDomain.h"
#include "UMCPHandler_SetMaterialProperty.generated.h"
#include "Material_SetProperty.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialProperty : public UObject, public IMCPHandler
UCLASS()
class UMCP_Material_SetProperty : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,15 +4,15 @@
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "UMCPHandler_DumpProperties.generated.h"
#include "Property_Dump.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpProperties : public UObject, public IMCPHandler
UCLASS()
class UMCP_Property_Dump : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,15 +4,15 @@
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "UMCPHandler_SetProperties.generated.h"
#include "Property_Set.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetProperties : public UObject, public IMCPHandler
UCLASS()
class UMCP_Property_Set : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -4,10 +4,10 @@
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "UMCPHandler_ShowCommands.generated.h"
#include "ShowCommands.generated.h"
UCLASS(meta=(Group="Documentation"))
class UMCPHandler_ShowCommands : public UObject, public IMCPHandler
UCLASS()
class UMCP_ShowCommands : public UObject, public IMCPHandler
{
GENERATED_BODY()
@@ -23,17 +23,32 @@ public:
return TEXT("List all available commands with their descriptions.");
}
void EmitGroup(const FString& GroupName, const TArray<UClass*>& Classes, FStringBuilderBase& Result)
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
Result.Appendf(TEXT("\n=== %s ===\n\n"), *GroupName);
for (UClass* Class : Classes)
FString QueryLower = Query.ToLower();
FString PrevGroup;
for (UClass* Class : MCPUtils::CollectHandlerClasses())
{
FString ToolName = MCPUtils::GetToolName(Class);
if (!ToolName.ToLower().Contains(QueryLower))
continue;
// Blank line between groups
FString Group = MCPUtils::GetToolGroup(Class);
if (Group != PrevGroup)
{
if (!PrevGroup.IsEmpty())
Result.Append(TEXT("\n"));
PrevGroup = Group;
}
if (Verbose)
{
MCPUtils::FormatCommandHelp(Class, Result);
continue;
}
Result.Append(MCPUtils::GetToolName(Class));
Result.Append(ToolName);
Result.Append(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(Class, EFieldIterationFlags::None); PropIt; ++PropIt)
@@ -47,36 +62,6 @@ public:
}
Result.Append(TEXT(")\n"));
}
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
FString QueryLower = Query.ToLower();
// Group handlers by their Group metadata.
TMap<FString, TArray<UClass*>> Groups;
for (UClass* Class : MCPUtils::CollectHandlerClasses())
{
FString ToolName = MCPUtils::GetToolName(Class);
if (!ToolName.ToLower().Contains(QueryLower))
continue;
FString Group = Class->GetMetaData(TEXT("Group"));
if (Group.IsEmpty()) Group = TEXT("Unclassified");
Groups.FindOrAdd(Group).Add(Class);
}
// Emit high-priority groups first, in order.
static const TCHAR* HighPriority[] = { TEXT("Documentation") };
for (const TCHAR* HP : HighPriority)
{
TArray<UClass*> Classes;
if (Groups.RemoveAndCopyValue(HP, Classes))
EmitGroup(HP, Classes, Result);
}
// Emit remaining groups.
for (const auto& Pair : Groups)
EmitGroup(Pair.Key, Pair.Value, Result);
// Append Path documentation.
Result.Append(TEXT("\n"));

View File

@@ -12,15 +12,15 @@
#include "AnimGraphNode_SequencePlayer.h"
#include "AnimStateNode.h"
#include "AnimationStateMachineGraph.h"
#include "UMCPHandler_AddAnimStateToMachine.generated.h"
#include "StateMachine_AddState.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddAnimStateToMachine : public UObject, public IMCPHandler
UCLASS()
class UMCP_StateMachine_AddState : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "AnimStateNode.h"
#include "AnimStateTransitionNode.h"
#include "AnimationStateMachineGraph.h"
#include "UMCPHandler_AddAnimStateTransition.generated.h"
#include "StateMachine_AddTransition.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddAnimStateTransition : public UObject, public IMCPHandler
UCLASS()
class UMCP_StateMachine_AddTransition : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -9,15 +9,15 @@
#include "AnimStateNode.h"
#include "AnimStateTransitionNode.h"
#include "AnimationStateMachineGraph.h"
#include "UMCPHandler_RemoveAnimStateFromMachine.generated.h"
#include "StateMachine_RemoveState.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveAnimStateFromMachine : public UObject, public IMCPHandler
UCLASS()
class UMCP_StateMachine_RemoveState : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -13,15 +13,15 @@
#include "AnimGraphNode_SequencePlayer.h"
#include "AnimStateNode.h"
#include "AnimationStateMachineGraph.h"
#include "UMCPHandler_SetAnimStateAnimation.generated.h"
#include "StateMachine_SetAnimation.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetAnimStateAnimation : public UObject, public IMCPHandler
UCLASS()
class UMCP_StateMachine_SetAnimation : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -16,15 +16,15 @@
#include "AnimStateNode.h"
#include "AnimationStateMachineGraph.h"
#include "K2Node_VariableGet.h"
#include "UMCPHandler_SetAnimStateBlendSpace.generated.h"
#include "StateMachine_SetBlendSpace.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetAnimStateBlendSpace : public UObject, public IMCPHandler
UCLASS()
class UMCP_StateMachine_SetBlendSpace : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -8,15 +8,15 @@
#include "Animation/AnimBlueprint.h"
#include "AnimStateTransitionNode.h"
#include "AnimationStateMachineGraph.h"
#include "UMCPHandler_SetAnimTransitionRule.generated.h"
#include "StateMachine_SetTransitionRule.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetAnimTransitionRule : public UObject, public IMCPHandler
UCLASS()
class UMCP_StateMachine_SetTransitionRule : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -10,7 +10,7 @@
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "Factories/StructureFactory.h"
#include "UMCPHandler_CreateStructAsset.generated.h"
#include "Struct_Create.generated.h"
// ---------------------------------------------------------------------------
@@ -29,8 +29,8 @@ struct FStructPropertyEntry
FString Type;
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateStructAsset : public UObject, public IMCPHandler
UCLASS()
class UMCP_Struct_Create : public UObject, public IMCPHandler
{
GENERATED_BODY()

View File

@@ -40,11 +40,6 @@ is actually fine — but it's a one-way door.
lookup failure instead of silently inserting a blank sample.
Probably better behavior, but different.
## Static Function Violation
- **CompileBlueprint** — has a `static` `CompileAndReport`
method, violating the no-static-functions rule.
## Minor Concerns
- **SetNodePositions** — node search across all graphs could

View File

@@ -1,169 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialFunction.h"
#include "Materials/MaterialExpression.h"
#include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "UObject/UObjectIterator.h"
#include "UMCPHandler_AddMaterialExpression.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddMaterialExpression : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Optional, Description="Material name or package path (specify this or materialFunction, not both)"))
FString Material;
UPROPERTY(meta=(Optional, Description="Material function name or package path (specify this or material, not both)"))
FString MaterialFunction;
UPROPERTY(meta=(Description="Expression class name without 'MaterialExpression' prefix (e.g. 'Constant', 'ScalarParameter', 'Add', 'Multiply', 'Lerp')"))
FString ExpressionClass;
UPROPERTY(meta=(Optional, Description="X position in the material graph editor"))
int32 PosX = 0;
UPROPERTY(meta=(Optional, Description="Y position in the material graph editor"))
int32 PosY = 0;
virtual FString GetDescription() const override
{
return TEXT("Add a new expression node to a material or material function graph.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (Material.IsEmpty() && MaterialFunction.IsEmpty())
{
Result.Append(TEXT("ERROR: Specify 'material' or 'materialFunction'\n"));
return;
}
if (!Material.IsEmpty() && !MaterialFunction.IsEmpty())
{
Result.Append(TEXT("ERROR: Specify 'material' or 'materialFunction', not both\n"));
return;
}
// Resolve the expression class
UClass* ExprClass = ResolveExpressionClass(Result);
if (!ExprClass) return;
// Load material or material function
UMaterial* MaterialObj = nullptr;
UMaterialFunction* MatFunc = nullptr;
UObject* Owner = nullptr;
if (!MaterialFunction.IsEmpty())
{
MCPAssets<UMaterialFunction> Assets;
if (!Assets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
MatFunc = Assets.Object();
Owner = MatFunc;
}
else
{
MCPAssets<UMaterial> Assets;
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
MaterialObj = Assets.Object();
Owner = MaterialObj;
}
// Ensure the MaterialGraph exists (commandlet mode doesn't auto-create it)
if (MaterialObj) MCPUtils::EnsureMaterialGraph(MaterialObj);
// Create the expression
UMaterialExpression* NewExpr = NewObject<UMaterialExpression>(Owner, ExprClass);
if (!NewExpr)
{
Result.Append(TEXT("ERROR: Failed to create material expression object\n"));
return;
}
NewExpr->MaterialExpressionEditorX = PosX;
NewExpr->MaterialExpressionEditorY = PosY;
if (MaterialObj)
{
MaterialObj->GetExpressionCollection().AddExpression(NewExpr);
if (MaterialObj->MaterialGraph)
MaterialObj->MaterialGraph->RebuildGraph();
MaterialObj->PreEditChange(nullptr);
MaterialObj->PostEditChange();
MaterialObj->MarkPackageDirty();
}
else
{
MatFunc->GetExpressionCollection().AddExpression(NewExpr);
MatFunc->PreEditChange(nullptr);
MatFunc->PostEditChange();
MatFunc->MarkPackageDirty();
}
// Save
bool bSaved = MaterialObj
? MCPUtils::SaveMaterialPackage(MaterialObj)
: MCPUtils::SaveGenericPackage(MatFunc);
// Output
Result.Appendf(TEXT("Added %s\n"), *MCPUtils::FormatName(NewExpr));
// Find the graph node GUID (only for materials with a material graph)
if (MaterialObj && MaterialObj->MaterialGraph)
{
for (UEdGraphNode* Node : MaterialObj->MaterialGraph->Nodes)
{
UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(Node);
if (MatNode && MatNode->MaterialExpression == NewExpr)
{
Result.Appendf(TEXT("NodeId: %s\n"), *Node->NodeGuid.ToString());
break;
}
}
}
if (!bSaved)
Result.Append(TEXT("WARNING: Failed to save package\n"));
}
private:
UClass* ResolveExpressionClass(FStringBuilderBase& Result)
{
// Convenience aliases
static TMap<FString, FString> Aliases = {
{TEXT("Lerp"), TEXT("LinearInterpolate")},
};
FString LookupName = ExpressionClass;
if (const FString* Alias = Aliases.Find(ExpressionClass))
LookupName = *Alias;
FString FullClassName = FString::Printf(TEXT("MaterialExpression%s"), *LookupName);
for (TObjectIterator<UClass> It; It; ++It)
{
if (It->GetName() == FullClassName && It->IsChildOf(UMaterialExpression::StaticClass()))
{
if (It->HasAnyClassFlags(CLASS_Abstract))
{
Result.Appendf(TEXT("ERROR: Expression class '%s' is abstract\n"), *ExpressionClass);
return nullptr;
}
return *It;
}
}
Result.Appendf(TEXT("ERROR: Unknown expression class '%s'. Use the UMaterialExpression subclass name without the 'MaterialExpression' prefix (e.g. 'Constant', 'ScalarParameter', 'Add', 'Multiply', 'Lerp')\n"),
*ExpressionClass);
return nullptr;
}
};

View File

@@ -1,188 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialFunction.h"
#include "Materials/MaterialExpression.h"
#include "MaterialGraph/MaterialGraph.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "UMCPHandler_ConnectMaterialExpressionPins.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
USTRUCT()
struct FConnectMaterialPinsEntry
{
GENERATED_BODY()
UPROPERTY()
FString SourceNode;
UPROPERTY()
FString SourcePin;
UPROPERTY()
FString TargetNode;
UPROPERTY()
FString TargetPin;
};
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ConnectMaterialExpressionPins : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Optional, Description="Material name or package path (specify this or materialFunction)"))
FString Material;
UPROPERTY(meta=(Optional, Description="Material function name or package path (specify this or material)"))
FString MaterialFunction;
UPROPERTY(meta=(Description="Array of {sourceNode, sourcePin, targetNode, targetPin} objects"))
FMCPJsonArray Connections;
virtual FString GetDescription() const override
{
return TEXT("Connect pins between nodes in a material or material function graph. Supports batching.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (Material.IsEmpty() && MaterialFunction.IsEmpty())
{
Result.Append(TEXT("ERROR: Specify 'material' or 'materialFunction'.\n"));
return;
}
// Load material or material function
UMaterial* MaterialObj = nullptr;
UMaterialFunction* MatFunc = nullptr;
if (!MaterialFunction.IsEmpty())
{
MCPAssets<UMaterialFunction> Assets;
if (!Assets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
MatFunc = Assets.Object();
}
else
{
MCPAssets<UMaterial> Assets;
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
MaterialObj = Assets.Object();
}
if (MaterialObj) MCPUtils::EnsureMaterialGraph(MaterialObj);
UEdGraph* Graph = MaterialObj ? (UEdGraph*)MaterialObj->MaterialGraph : (MatFunc ? MatFunc->MaterialGraph : nullptr);
if (!Graph)
{
Result.Appendf(TEXT("ERROR: %s has no material graph.\n"),
MaterialObj ? *MCPUtils::FormatName(MaterialObj) : *MCPUtils::FormatName(MatFunc));
return;
}
int32 SuccessCount = 0;
const UEdGraphSchema* Schema = Graph->GetSchema();
for (const TSharedPtr<FJsonValue>& ConnVal : Connections.Array)
{
FConnectMaterialPinsEntry Entry;
if (!MCPUtils::PopulateFromJson(FConnectMaterialPinsEntry::StaticStruct(), &Entry, ConnVal, MCPErrorCallback(Result)))
continue;
// Find source node
UEdGraphNode* SrcNode = FindNodeByName(Graph, Entry.SourceNode);
if (!SrcNode)
{
Result.Appendf(TEXT("ERROR: Source node '%s' not found.\n"), *Entry.SourceNode);
continue;
}
// Find target node
UEdGraphNode* TgtNode = FindNodeByName(Graph, Entry.TargetNode);
if (!TgtNode)
{
Result.Appendf(TEXT("ERROR: Target node '%s' not found.\n"), *Entry.TargetNode);
continue;
}
// Find source pin
UEdGraphPin* SrcPin = FindPinByName(SrcNode, Entry.SourcePin);
if (!SrcPin)
{
Result.Appendf(TEXT("ERROR: Pin '%s' not found on %s. Available:"),
*Entry.SourcePin, *MCPUtils::FormatName(SrcNode));
for (UEdGraphPin* P : SrcNode->Pins)
if (P) Result.Appendf(TEXT(" %s"), *MCPUtils::FormatName(P));
Result.Append(TEXT("\n"));
continue;
}
// Find target pin
UEdGraphPin* TgtPin = FindPinByName(TgtNode, Entry.TargetPin);
if (!TgtPin)
{
Result.Appendf(TEXT("ERROR: Pin '%s' not found on %s. Available:"),
*Entry.TargetPin, *MCPUtils::FormatName(TgtNode));
for (UEdGraphPin* P : TgtNode->Pins)
if (P) Result.Appendf(TEXT(" %s"), *MCPUtils::FormatName(P));
Result.Append(TEXT("\n"));
continue;
}
// Check compatibility
const FPinConnectionResponse Response = Schema->CanCreateConnection(SrcPin, TgtPin);
if (Response.Response == CONNECT_RESPONSE_DISALLOW)
{
Result.Appendf(TEXT("ERROR: Cannot connect %s.%s -> %s.%s: %s\n"),
*MCPUtils::FormatName(SrcNode), *MCPUtils::FormatName(SrcPin),
*MCPUtils::FormatName(TgtNode), *MCPUtils::FormatName(TgtPin),
*Response.Message.ToString());
continue;
}
Schema->TryCreateConnection(SrcPin, TgtPin);
SuccessCount++;
}
if (SuccessCount > 0)
{
UObject* Asset = MaterialObj ? (UObject*)MaterialObj : (UObject*)MatFunc;
Asset->PreEditChange(nullptr);
Asset->PostEditChange();
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
Result.Appendf(TEXT("Connected %d/%d. Saved: %s\n"),
SuccessCount, Connections.Array.Num(), bSaved ? TEXT("yes") : TEXT("no"));
}
else
{
Result.Appendf(TEXT("0/%d connections succeeded.\n"), Connections.Array.Num());
}
}
private:
UEdGraphNode* FindNodeByName(UEdGraph* Graph, const FString& Name)
{
for (UEdGraphNode* Node : Graph->Nodes)
if (Node && MCPUtils::Identifies(Name, Node))
return Node;
return nullptr;
}
UEdGraphPin* FindPinByName(UEdGraphNode* Node, const FString& Name)
{
for (UEdGraphPin* Pin : Node->Pins)
if (Pin && MCPUtils::Identifies(Name, Pin))
return Pin;
return nullptr;
}
};

View File

@@ -1,126 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialFunction.h"
#include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "UMCPHandler_DeleteMaterialExpression.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteMaterialExpression : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Optional, Description="Material name or package path (specify this or materialFunction)"))
FString Material;
UPROPERTY(meta=(Optional, Description="Material function name or package path (specify this or material)"))
FString MaterialFunction;
UPROPERTY(meta=(Description="Expression name (use FormatName from DumpMaterial output)"))
FString Node;
UPROPERTY(meta=(Optional, Description="If true, preview the change without applying it"))
bool DryRun = false;
virtual FString GetDescription() const override
{
return TEXT("Remove an expression node from a material or material function graph.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (Material.IsEmpty() && MaterialFunction.IsEmpty())
{
MCPErrorCallback(Result).SetError(TEXT("Specify 'material' or 'materialFunction'."));
return;
}
// Load material or material function
UMaterial* MaterialObj = nullptr;
UMaterialFunction* MatFunc = nullptr;
if (!MaterialFunction.IsEmpty())
{
MCPAssets<UMaterialFunction> MFAssets;
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
MatFunc = MFAssets.Object();
}
else
{
MCPAssets<UMaterial> MatAssets;
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
MaterialObj = MatAssets.Object();
}
if (MaterialObj) MCPUtils::EnsureMaterialGraph(MaterialObj);
UEdGraph* Graph = MaterialObj ? (UEdGraph*)MaterialObj->MaterialGraph : (MatFunc ? MatFunc->MaterialGraph : nullptr);
if (!Graph)
{
MCPErrorCallback(Result).SetError(TEXT("Asset has no material graph."));
return;
}
// Find node by name
UMaterialGraphNode* TargetMatNode = nullptr;
for (UEdGraphNode* GraphNode : Graph->Nodes)
{
if (!GraphNode) continue;
UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(GraphNode);
if (!MatNode || !MatNode->MaterialExpression) continue;
if (MCPUtils::Identifies(Node, MatNode->MaterialExpression))
{
TargetMatNode = MatNode;
break;
}
}
if (!TargetMatNode)
{
MCPErrorCallback(Result).SetError(FString::Printf(TEXT("Expression '%s' not found."), *Node));
return;
}
FString ExprName = MCPUtils::FormatName(TargetMatNode->MaterialExpression);
if (DryRun)
{
Result.Appendf(TEXT("DryRun: would delete %s\n"), *ExprName);
return;
}
// Remove the expression
UMaterialExpression* ExprToRemove = TargetMatNode->MaterialExpression;
if (MaterialObj)
MaterialObj->GetExpressionCollection().RemoveExpression(ExprToRemove);
else
MatFunc->GetExpressionCollection().RemoveExpression(ExprToRemove);
ExprToRemove->MarkAsGarbage();
// Rebuild graph
Graph->NotifyGraphChanged();
UObject* Asset = MaterialObj ? (UObject*)MaterialObj : (UObject*)MatFunc;
Asset->PreEditChange(nullptr);
Asset->PostEditChange();
Asset->MarkPackageDirty();
// Save
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
Result.Appendf(TEXT("Deleted %s"), *ExprName);
if (!bSaved) Result.Append(TEXT(" (save failed)"));
Result.Append(TEXT("\n"));
}
};

View File

@@ -1,188 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionTextureObjectParameter.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Materials/MaterialExpressionConstant.h"
#include "Materials/MaterialExpressionConstant3Vector.h"
#include "Materials/MaterialExpressionConstant4Vector.h"
#include "Materials/MaterialExpressionTextureSample.h"
#include "Materials/MaterialExpressionMaterialFunctionCall.h"
#include "Materials/MaterialFunction.h"
#include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "MaterialGraph/MaterialGraphNode_Root.h"
#include "MaterialGraph/MaterialGraphSchema.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "UMCPHandler_DescribeMaterialInEnglish.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DescribeMaterialInEnglish : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material name or package path"))
FString Material;
virtual FString GetDescription() const override
{
return TEXT("Generate a human-readable description of a material by tracing its expression graph from the root node inputs.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPAssets<UMaterial> Assets;
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
UMaterial* MaterialObj = Assets.Object();
// Ensure material graph is built
MCPUtils::EnsureMaterialGraph(MaterialObj);
if (!MaterialObj->MaterialGraph)
{
MCPErrorCallback(Result).SetError(TEXT("Could not build MaterialGraph for this material"));
return;
}
// Find root node
UMaterialGraphNode_Root* RootNode = nullptr;
for (UEdGraphNode* Node : MaterialObj->MaterialGraph->Nodes)
{
RootNode = Cast<UMaterialGraphNode_Root>(Node);
if (RootNode) break;
}
if (!RootNode)
{
MCPErrorCallback(Result).SetError(TEXT("Could not find root node in material graph"));
return;
}
// Recursive helper: trace backwards from a pin and build a description string
TFunction<FString(UEdGraphPin*, int32)> TracePin = [&TracePin](UEdGraphPin* Pin, int32 Depth) -> FString
{
if (!Pin || Depth > 10)
return TEXT("(unknown)");
if (Pin->LinkedTo.Num() == 0)
{
if (!Pin->DefaultValue.IsEmpty())
return FString::Printf(TEXT("(default: %s)"), *Pin->DefaultValue);
return TEXT("(unconnected)");
}
TArray<FString> Sources;
for (UEdGraphPin* LinkedPin : Pin->LinkedTo)
{
if (!LinkedPin || !LinkedPin->GetOwningNode()) continue;
UEdGraphNode* SourceNode = LinkedPin->GetOwningNode();
FString NodeDesc;
UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(SourceNode);
if (!MatNode)
{
NodeDesc = MCPUtils::FormatName(SourceNode);
Sources.Add(NodeDesc);
continue;
}
UMaterialExpression* Expr = MatNode->MaterialExpression;
if (!Expr)
{
NodeDesc = TEXT("(null expression)");
}
else if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
{
NodeDesc = FString::Printf(TEXT("ScalarParam \"%s\" (default: %.4f)"), *SP->ParameterName.ToString(), SP->DefaultValue);
}
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
{
NodeDesc = FString::Printf(TEXT("VectorParam \"%s\" (default: R=%.2f G=%.2f B=%.2f A=%.2f)"),
*VP->ParameterName.ToString(), VP->DefaultValue.R, VP->DefaultValue.G, VP->DefaultValue.B, VP->DefaultValue.A);
}
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
{
FString TexName = TP->Texture ? MCPUtils::FormatName(TP->Texture) : TEXT("None");
NodeDesc = FString::Printf(TEXT("TextureParam \"%s\" (%s)"), *TP->ParameterName.ToString(), *TexName);
}
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
{
NodeDesc = FString::Printf(TEXT("StaticSwitchParam \"%s\" (default: %s)"),
*SSP->ParameterName.ToString(), SSP->DefaultValue ? TEXT("true") : TEXT("false"));
}
else if (auto* SC = Cast<UMaterialExpressionConstant>(Expr))
{
NodeDesc = FString::Printf(TEXT("Constant(%.4f)"), SC->R);
}
else if (auto* C3 = Cast<UMaterialExpressionConstant3Vector>(Expr))
{
NodeDesc = FString::Printf(TEXT("Constant3(R=%.2f G=%.2f B=%.2f)"), C3->Constant.R, C3->Constant.G, C3->Constant.B);
}
else if (auto* C4 = Cast<UMaterialExpressionConstant4Vector>(Expr))
{
NodeDesc = FString::Printf(TEXT("Constant4(R=%.2f G=%.2f B=%.2f A=%.2f)"), C4->Constant.R, C4->Constant.G, C4->Constant.B, C4->Constant.A);
}
else if (auto* TS = Cast<UMaterialExpressionTextureSample>(Expr))
{
FString TexName = TS->Texture ? MCPUtils::FormatName(TS->Texture) : TEXT("None");
NodeDesc = FString::Printf(TEXT("TextureSample(%s)"), *TexName);
}
else if (auto* MFC = Cast<UMaterialExpressionMaterialFunctionCall>(Expr))
{
FString FuncName = MFC->MaterialFunction ? MFC->MaterialFunction->GetPathName() : TEXT("None");
NodeDesc = FString::Printf(TEXT("FunctionCall(%s)"), *FuncName);
}
else
{
NodeDesc = MCPUtils::FormatName(Expr);
}
// Recurse into input pins
TArray<FString> InputDescs;
for (UEdGraphPin* InputPin : SourceNode->Pins)
{
if (!InputPin || InputPin->Direction != EGPD_Input || InputPin->LinkedTo.Num() == 0) continue;
InputDescs.Add(TracePin(InputPin, Depth + 1));
}
if (InputDescs.Num() > 0)
{
NodeDesc += TEXT(" <- (") + FString::Join(InputDescs, TEXT(", ")) + TEXT(")");
}
Sources.Add(NodeDesc);
}
if (Sources.Num() == 1)
return Sources[0];
return TEXT("(") + FString::Join(Sources, TEXT(", ")) + TEXT(")");
};
// Trace each connected root input and output plain text
Result.Appendf(TEXT("Material: %s\n\n"), *MCPUtils::FormatName(MaterialObj));
for (UEdGraphPin* Pin : RootNode->Pins)
{
if (!Pin || Pin->Direction != EGPD_Input) continue;
if (Pin->LinkedTo.Num() == 0) continue;
FString PinName = MCPUtils::FormatName(Pin);
FString Description = TracePin(Pin, 0);
Result.Appendf(TEXT("%s <- %s\n"), *PinName, *Description);
}
}
};

View File

@@ -1,98 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialFunction.h"
#include "MaterialGraph/MaterialGraph.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "UMCPHandler_DisconnectMaterialExpressionPin.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DisconnectMaterialExpressionPin : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Optional, Description="Material name or package path (specify this or materialFunction)"))
FString Material;
UPROPERTY(meta=(Optional, Description="Material function name or package path (specify this or material)"))
FString MaterialFunction;
UPROPERTY(meta=(Description="Node name (use FormatName-style identifier)"))
FString Node;
UPROPERTY(meta=(Description="Pin name to disconnect"))
FString PinName;
virtual FString GetDescription() const override
{
return TEXT("Break all connections on a specific pin in a material or material function graph.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (Material.IsEmpty() && MaterialFunction.IsEmpty())
{
Result.Append(TEXT("ERROR: Specify 'material' or 'materialFunction'.\n"));
return;
}
// Load material or material function
UMaterial* MaterialObj = nullptr;
UMaterialFunction* MatFunc = nullptr;
if (!MaterialFunction.IsEmpty())
{
MCPAssets<UMaterialFunction> Assets;
if (!Assets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
MatFunc = Assets.Object();
}
else
{
MCPAssets<UMaterial> Assets;
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
MaterialObj = Assets.Object();
}
if (MaterialObj) MCPUtils::EnsureMaterialGraph(MaterialObj);
UEdGraph* Graph = MaterialObj ? (UEdGraph*)MaterialObj->MaterialGraph : (MatFunc ? MatFunc->MaterialGraph : nullptr);
if (!Graph)
{
Result.Appendf(TEXT("ERROR: %s has no material graph.\n"),
MaterialObj ? *MCPUtils::FormatName(MaterialObj) : *MCPUtils::FormatName(MatFunc));
return;
}
// Find node and pin via MCPFetcher
MCPFetcher F(Result, Graph);
UEdGraphPin* Pin = F.Node(Node).Pin(PinName).Cast<UEdGraphPin>();
if (!Pin) return;
int32 BrokenCount = Pin->LinkedTo.Num();
Pin->BreakAllPinLinks();
UObject* Asset = MaterialObj ? (UObject*)MaterialObj : (UObject*)MatFunc;
Asset->PreEditChange(nullptr);
Asset->PostEditChange();
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
Result.Appendf(TEXT("Disconnected %d link(s) from %s on %s.\n"),
BrokenCount, *MCPUtils::FormatName(Pin), *MCPUtils::FormatName(Pin->GetOwningNode()));
if (!bSaved)
Result.Append(TEXT("WARNING: Failed to save package.\n"));
}
};

View File

@@ -1,228 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "MaterialDomain.h"
#include "Materials/MaterialInstanceConstant.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Materials/MaterialExpressionTextureSample.h"
#include "Engine/Texture.h"
#include "UMCPHandler_DumpMaterial.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpMaterial : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material or MaterialInstance name or package path"))
FString Material;
virtual FString GetDescription() const override
{
return TEXT("Get detailed info about a material or material instance, including parameters, usage flags, and referenced textures.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPAssets<UMaterialInterface> Assets;
Assets.NoScans();
Assets.Scan<UMaterial>();
Assets.Scan<UMaterialInstanceConstant>();
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
UMaterialInterface* LoadedObj = Assets.Object();
if (UMaterial* Mat = Cast<UMaterial>(LoadedObj))
{
EmitMaterial(Mat, Result);
return;
}
if (UMaterialInstanceConstant* MI = Cast<UMaterialInstanceConstant>(LoadedObj))
{
EmitMaterialInstance(MI, Result);
return;
}
Result.Appendf(TEXT("ERROR: Loaded object is %s, expected Material or MaterialInstance.\n"),
*LoadedObj->GetClass()->GetName());
}
private:
void EmitMaterial(UMaterial* Mat, FStringBuilderBase& Result)
{
Result.Appendf(TEXT("Material: %s\n"), *MCPUtils::FormatName(Mat));
Result.Appendf(TEXT("Domain: %s\n"), *MCPUtils::EnumToString(Mat->MaterialDomain, TEXT("MD_")));
Result.Appendf(TEXT("BlendMode: %s\n"), *MCPUtils::EnumToString(Mat->BlendMode, TEXT("BLEND_")));
Result.Appendf(TEXT("TwoSided: %s\n"), Mat->IsTwoSided() ? TEXT("true") : TEXT("false"));
// Shading models
FMaterialShadingModelField SMField = Mat->GetShadingModels();
const UEnum* SMEnum = StaticEnum<EMaterialShadingModel>();
TArray<FString> SMNames;
for (int32 i = 0; i < SMEnum->NumEnums() - 1; ++i)
{
EMaterialShadingModel SM = (EMaterialShadingModel)SMEnum->GetValueByIndex(i);
if (SMField.HasShadingModel(SM))
SMNames.Add(SMEnum->GetNameStringByIndex(i));
}
Result.Appendf(TEXT("ShadingModels: %s\n"), *FString::Join(SMNames, TEXT(", ")));
// Parameters
auto Expressions = Mat->GetExpressions();
bool bHasParams = false;
for (UMaterialExpression* Expr : Expressions)
{
if (!Expr) continue;
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
{
if (!bHasParams) { Result.Append(TEXT("\nParameters:\n")); bHasParams = true; }
Result.Appendf(TEXT(" Scalar \"%s\" = %g"), *SP->ParameterName.ToString(), SP->DefaultValue);
if (!SP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *SP->Group.ToString());
Result.Append(TEXT("\n"));
}
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
{
if (!bHasParams) { Result.Append(TEXT("\nParameters:\n")); bHasParams = true; }
Result.Appendf(TEXT(" Vector \"%s\" = (%.3f, %.3f, %.3f, %.3f)"),
*VP->ParameterName.ToString(),
VP->DefaultValue.R, VP->DefaultValue.G, VP->DefaultValue.B, VP->DefaultValue.A);
if (!VP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *VP->Group.ToString());
Result.Append(TEXT("\n"));
}
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
{
if (!bHasParams) { Result.Append(TEXT("\nParameters:\n")); bHasParams = true; }
Result.Appendf(TEXT(" Texture \"%s\" = %s"),
*TP->ParameterName.ToString(),
TP->Texture ? *MCPUtils::FormatName(TP->Texture) : TEXT("None"));
if (!TP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *TP->Group.ToString());
Result.Append(TEXT("\n"));
}
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
{
if (!bHasParams) { Result.Append(TEXT("\nParameters:\n")); bHasParams = true; }
Result.Appendf(TEXT(" StaticSwitch \"%s\" = %s"),
*SSP->ParameterName.ToString(),
SSP->DefaultValue ? TEXT("true") : TEXT("false"));
if (!SSP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *SSP->Group.ToString());
Result.Append(TEXT("\n"));
}
}
// Referenced textures
auto RefTexObjs = Mat->GetReferencedTextures();
bool bHasTextures = false;
for (const TObjectPtr<UObject>& TexObj : RefTexObjs)
{
if (!TexObj) continue;
if (!bHasTextures) { Result.Append(TEXT("\nReferenced Textures:\n")); bHasTextures = true; }
if (UTexture* Tex = Cast<UTexture>(TexObj.Get()))
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Tex));
else
Result.Appendf(TEXT(" %s\n"), *TexObj->GetPathName());
}
// Usage flags — only print enabled ones
Result.Append(TEXT("\nUsage Flags:"));
bool bAnyUsage = false;
auto EmitFlag = [&](bool bSet, const TCHAR* Name) {
if (bSet) { Result.Appendf(TEXT(" %s"), Name); bAnyUsage = true; }
};
EmitFlag(Mat->bUsedWithSkeletalMesh, TEXT("SkeletalMesh"));
EmitFlag(Mat->bUsedWithMorphTargets, TEXT("MorphTargets"));
EmitFlag(Mat->bUsedWithNiagaraSprites, TEXT("NiagaraSprites"));
EmitFlag(Mat->bUsedWithParticleSprites, TEXT("ParticleSprites"));
EmitFlag(Mat->bUsedWithStaticLighting, TEXT("StaticLighting"));
if (!bAnyUsage) Result.Append(TEXT(" (none)"));
Result.Append(TEXT("\n"));
// Stats
Result.Appendf(TEXT("Expressions: %d\n"), Expressions.Num());
int32 TextureSampleCount = 0;
for (UMaterialExpression* Expr : Expressions)
if (Expr && Expr->IsA<UMaterialExpressionTextureSample>())
TextureSampleCount++;
Result.Appendf(TEXT("TextureSamples: %d\n"), TextureSampleCount);
if (Mat->MaterialGraph)
Result.Appendf(TEXT("GraphNodes: %d\n"), Mat->MaterialGraph->Nodes.Num());
// Additional settings — only print non-default values
if (Mat->OpacityMaskClipValue != 0.3333f)
Result.Appendf(TEXT("OpacityMaskClipValue: %g\n"), Mat->OpacityMaskClipValue);
if (Mat->DitheredLODTransition)
Result.Append(TEXT("DitheredLODTransition: true\n"));
if (Mat->bAllowNegativeEmissiveColor)
Result.Append(TEXT("AllowNegativeEmissiveColor: true\n"));
}
void EmitMaterialInstance(UMaterialInstanceConstant* MI, FStringBuilderBase& Result)
{
Result.Appendf(TEXT("MaterialInstance: %s\n"), *MCPUtils::FormatName(MI));
if (MI->Parent)
{
if (UMaterial* ParentMat = Cast<UMaterial>(MI->Parent))
Result.Appendf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentMat));
else if (UMaterialInstance* ParentMI = Cast<UMaterialInstance>(MI->Parent))
Result.Appendf(TEXT("Parent: %s\n"), *MCPUtils::FormatName(ParentMI));
else
Result.Appendf(TEXT("Parent: %s\n"), *MI->Parent->GetPathName());
}
// Overridden parameters
bool bHasParams = false;
auto EnsureHeader = [&]() {
if (!bHasParams) { Result.Append(TEXT("\nOverridden Parameters:\n")); bHasParams = true; }
};
for (const FScalarParameterValue& P : MI->ScalarParameterValues)
{
EnsureHeader();
Result.Appendf(TEXT(" Scalar \"%s\" = %g\n"), *P.ParameterInfo.Name.ToString(), P.ParameterValue);
}
for (const FVectorParameterValue& P : MI->VectorParameterValues)
{
EnsureHeader();
Result.Appendf(TEXT(" Vector \"%s\" = (%.3f, %.3f, %.3f, %.3f)\n"),
*P.ParameterInfo.Name.ToString(),
P.ParameterValue.R, P.ParameterValue.G, P.ParameterValue.B, P.ParameterValue.A);
}
for (const FTextureParameterValue& P : MI->TextureParameterValues)
{
EnsureHeader();
if (P.ParameterValue)
{
Result.Appendf(TEXT(" Texture \"%s\" = %s\n"),
*P.ParameterInfo.Name.ToString(), *MCPUtils::FormatName(P.ParameterValue));
}
else
{
Result.Appendf(TEXT(" Texture \"%s\" = None\n"), *P.ParameterInfo.Name.ToString());
}
}
for (const FStaticSwitchParameter& P : MI->GetStaticParameters().StaticSwitchParameters)
{
EnsureHeader();
Result.Appendf(TEXT(" StaticSwitch \"%s\" = %s%s\n"),
*P.ParameterInfo.Name.ToString(),
P.Value ? TEXT("true") : TEXT("false"),
P.bOverride ? TEXT("") : TEXT(" (not overridden)"));
}
}
};

View File

@@ -1,147 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/MaterialFunction.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialExpressionFunctionInput.h"
#include "Materials/MaterialExpressionFunctionOutput.h"
#include "Materials/MaterialExpressionMaterialFunctionCall.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "Materials/MaterialExpressionConstant.h"
#include "Materials/MaterialExpressionConstant3Vector.h"
#include "Materials/MaterialExpressionConstant4Vector.h"
#include "Materials/MaterialExpressionTextureObjectParameter.h"
#include "Materials/MaterialExpressionTextureSample.h"
#include "Materials/MaterialExpressionTextureCoordinate.h"
#include "Materials/MaterialExpressionComponentMask.h"
#include "Materials/MaterialExpressionCustom.h"
#include "Engine/Texture.h"
#include "UMCPHandler_DumpMaterialFunction.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpMaterialFunction : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="MaterialFunction name or package path"))
FString MaterialFunction;
virtual FString GetDescription() const override
{
return TEXT("Get detailed info about a material function, including its inputs, outputs, and expressions.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPAssets<UMaterialFunction> Assets;
if (!Assets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
UMaterialFunction* MF = Assets.Object();
Result.Appendf(TEXT("MaterialFunction: %s\n"), *MCPUtils::FormatName(MF));
FString Desc = MF->GetDescription();
if (!Desc.IsEmpty())
Result.Appendf(TEXT("Description: %s\n"), *Desc);
auto Expressions = MF->GetExpressions();
Result.Appendf(TEXT("Expressions: %d\n"), Expressions.Num());
// Inputs and outputs
bool bHasInputs = false;
bool bHasOutputs = false;
for (UMaterialExpression* Expr : Expressions)
{
if (!Expr) continue;
if (auto* FI = Cast<UMaterialExpressionFunctionInput>(Expr))
{
if (!bHasInputs) { Result.Append(TEXT("\nInputs:\n")); bHasInputs = true; }
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Expr));
}
else if (auto* FO = Cast<UMaterialExpressionFunctionOutput>(Expr))
{
if (!bHasOutputs) { Result.Append(TEXT("\nOutputs:\n")); bHasOutputs = true; }
Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Expr));
}
}
// All expressions
Result.Append(TEXT("\nExpression List:\n"));
for (UMaterialExpression* Expr : Expressions)
{
if (!Expr) continue;
Result.Appendf(TEXT(" %s"), *MCPUtils::FormatName(Expr));
EmitExpressionDetails(Expr, Result);
Result.Append(TEXT("\n"));
}
}
private:
void EmitExpressionDetails(UMaterialExpression* Expr, FStringBuilderBase& Result)
{
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
{
Result.Appendf(TEXT(" default=%g"), SP->DefaultValue);
if (!SP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *SP->Group.ToString());
}
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
{
Result.Appendf(TEXT(" default=(%.3f, %.3f, %.3f, %.3f)"),
VP->DefaultValue.R, VP->DefaultValue.G, VP->DefaultValue.B, VP->DefaultValue.A);
if (!VP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *VP->Group.ToString());
}
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
{
Result.Appendf(TEXT(" texture=%s"),
TP->Texture ? *MCPUtils::FormatName(TP->Texture) : TEXT("None"));
if (!TP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *TP->Group.ToString());
}
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
{
Result.Appendf(TEXT(" default=%s"), SSP->DefaultValue ? TEXT("true") : TEXT("false"));
if (!SSP->Group.IsNone()) Result.Appendf(TEXT(" [%s]"), *SSP->Group.ToString());
}
else if (auto* SC = Cast<UMaterialExpressionConstant>(Expr))
{
Result.Appendf(TEXT(" value=%g"), SC->R);
}
else if (auto* C3 = Cast<UMaterialExpressionConstant3Vector>(Expr))
{
Result.Appendf(TEXT(" value=(%.3f, %.3f, %.3f)"), C3->Constant.R, C3->Constant.G, C3->Constant.B);
}
else if (auto* C4 = Cast<UMaterialExpressionConstant4Vector>(Expr))
{
Result.Appendf(TEXT(" value=(%.3f, %.3f, %.3f, %.3f)"),
C4->Constant.R, C4->Constant.G, C4->Constant.B, C4->Constant.A);
}
else if (auto* FC = Cast<UMaterialExpressionMaterialFunctionCall>(Expr))
{
if (FC->MaterialFunction)
Result.Appendf(TEXT(" calls=%s"), *FC->MaterialFunction->GetPathName());
}
else if (auto* TS = Cast<UMaterialExpressionTextureSample>(Expr))
{
if (TS->Texture)
Result.Appendf(TEXT(" texture=%s"), *MCPUtils::FormatName(TS->Texture));
}
else if (auto* TC = Cast<UMaterialExpressionTextureCoordinate>(Expr))
{
Result.Appendf(TEXT(" index=%d tiling=(%.1f, %.1f)"), TC->CoordinateIndex, TC->UTiling, TC->VTiling);
}
else if (auto* Custom = Cast<UMaterialExpressionCustom>(Expr))
{
Result.Appendf(TEXT(" code_len=%d"), Custom->Code.Len());
}
}
};

View File

@@ -1,106 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionTextureSampleParameter2D.h"
#include "Materials/MaterialExpressionStaticSwitchParameter.h"
#include "UMCPHandler_SearchWithinMaterials.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchWithinMaterials : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Search query string to match against material names, expression classes, and parameter names"))
FString Query;
UPROPERTY(meta=(Optional, Description="Maximum number of results to return (default 50, max 200)"))
int32 MaxResults = 50;
virtual FString GetDescription() const override
{
return TEXT("Search across all materials for matching material names, expression types, and parameter names.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
FString DecodedQuery = MCPUtils::UrlDecode(Query);
MaxResults = FMath::Clamp(MaxResults, 1, 200);
int32 Count = 0;
MCPAssets<UMaterial> AllMaterials;
AllMaterials.Load();
for (UMaterial* MaterialObj : AllMaterials.Objects())
{
if (Count >= MaxResults) break;
if (!MaterialObj) continue;
FString MatName = MCPUtils::FormatName(MaterialObj);
// Check material name
bool bNameMatch = MatName.Contains(DecodedQuery, ESearchCase::IgnoreCase);
if (bNameMatch)
{
Result.Appendf(TEXT("material %s\n"), *MatName);
Count++;
}
// Search expressions
for (UMaterialExpression* Expr : MaterialObj->GetExpressions())
{
if (!Expr || Count >= MaxResults) continue;
FString ExprName = MCPUtils::FormatName(Expr);
FString ExprClass = Expr->GetClass()->GetName();
FString ExprDesc = Expr->GetDescription();
// Check parameter name
FString ParamName;
if (auto* SP = Cast<UMaterialExpressionScalarParameter>(Expr))
ParamName = SP->ParameterName.ToString();
else if (auto* VP = Cast<UMaterialExpressionVectorParameter>(Expr))
ParamName = VP->ParameterName.ToString();
else if (auto* TP = Cast<UMaterialExpressionTextureSampleParameter2D>(Expr))
ParamName = TP->ParameterName.ToString();
else if (auto* SSP = Cast<UMaterialExpressionStaticSwitchParameter>(Expr))
ParamName = SSP->ParameterName.ToString();
bool bExprMatch = ExprDesc.Contains(DecodedQuery, ESearchCase::IgnoreCase) ||
ExprClass.Contains(DecodedQuery, ESearchCase::IgnoreCase) ||
(!ParamName.IsEmpty() && ParamName.Contains(DecodedQuery, ESearchCase::IgnoreCase));
if (!bExprMatch) continue;
Result.Appendf(TEXT("expression %s in %s (%s)"), *ExprName, *MatName, *ExprClass);
if (!ParamName.IsEmpty())
Result.Appendf(TEXT(" param=%s"), *ParamName);
Result.Append(TEXT("\n"));
Count++;
}
}
if (Count == 0)
{
Result.Append(TEXT("No matches found.\n"));
}
else if (Count >= MaxResults)
{
Result.Appendf(TEXT("WARNING: Reached limit of %d results. Specify MaxResults to raise it.\n"), MaxResults);
}
}
};

View File

@@ -1,132 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialFunction.h"
#include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "UMCPHandler_SetMaterialExpressionPosition.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialExpressionPosition : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Optional, Description="Material name or package path (specify this or materialFunction)"))
FString Material;
UPROPERTY(meta=(Optional, Description="Material function name or package path (specify this or material)"))
FString MaterialFunction;
UPROPERTY(meta=(Description="Expression name (use FormatName from DumpMaterial output)"))
FString Node;
UPROPERTY(meta=(Description="New X position"))
int32 PosX = 0;
UPROPERTY(meta=(Description="New Y position"))
int32 PosY = 0;
UPROPERTY(meta=(Optional, Description="If true, preview the change without applying it"))
bool DryRun = false;
virtual FString GetDescription() const override
{
return TEXT("Reposition a material expression node in the material graph editor.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (Material.IsEmpty() && MaterialFunction.IsEmpty())
{
MCPErrorCallback(Result).SetError(TEXT("Specify 'material' or 'materialFunction'."));
return;
}
// Load material or material function
UMaterial* MaterialObj = nullptr;
UMaterialFunction* MatFunc = nullptr;
if (!MaterialFunction.IsEmpty())
{
MCPAssets<UMaterialFunction> MFAssets;
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
MatFunc = MFAssets.Object();
}
else
{
MCPAssets<UMaterial> MatAssets;
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
MaterialObj = MatAssets.Object();
}
if (MaterialObj) MCPUtils::EnsureMaterialGraph(MaterialObj);
UEdGraph* Graph = MaterialObj ? (UEdGraph*)MaterialObj->MaterialGraph : (MatFunc ? MatFunc->MaterialGraph : nullptr);
if (!Graph)
{
MCPErrorCallback(Result).SetError(TEXT("Asset has no material graph."));
return;
}
// Find node by name
UMaterialGraphNode* TargetMatNode = nullptr;
for (UEdGraphNode* GraphNode : Graph->Nodes)
{
if (!GraphNode) continue;
UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(GraphNode);
if (!MatNode || !MatNode->MaterialExpression) continue;
if (MCPUtils::Identifies(Node, MatNode->MaterialExpression))
{
TargetMatNode = MatNode;
break;
}
}
if (!TargetMatNode)
{
MCPErrorCallback(Result).SetError(FString::Printf(TEXT("Expression '%s' not found."), *Node));
return;
}
if (DryRun)
{
Result.Appendf(TEXT("DryRun: would move %s to (%d, %d)\n"),
*MCPUtils::FormatName(TargetMatNode->MaterialExpression), PosX, PosY);
return;
}
// Set position on the graph node
TargetMatNode->NodePosX = PosX;
TargetMatNode->NodePosY = PosY;
// Also update the underlying expression position
if (TargetMatNode->MaterialExpression)
{
TargetMatNode->MaterialExpression->MaterialExpressionEditorX = PosX;
TargetMatNode->MaterialExpression->MaterialExpressionEditorY = PosY;
}
UObject* Asset = MaterialObj ? (UObject*)MaterialObj : (UObject*)MatFunc;
Asset->PreEditChange(nullptr);
Asset->PostEditChange();
// Save
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
Result.Appendf(TEXT("Moved %s to (%d, %d)"),
*MCPUtils::FormatName(TargetMatNode->MaterialExpression), PosX, PosY);
if (!bSaved) Result.Append(TEXT(" (save failed)"));
Result.Append(TEXT("\n"));
}
};

View File

@@ -1,282 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialFunction.h"
#include "Materials/MaterialExpression.h"
#include "Materials/MaterialExpressionScalarParameter.h"
#include "Materials/MaterialExpressionVectorParameter.h"
#include "Materials/MaterialExpressionConstant.h"
#include "Materials/MaterialExpressionConstant3Vector.h"
#include "Materials/MaterialExpressionConstant4Vector.h"
#include "Materials/MaterialExpressionTextureSample.h"
#include "Materials/MaterialExpressionTextureCoordinate.h"
#include "Materials/MaterialExpressionComponentMask.h"
#include "Materials/MaterialExpressionCustom.h"
#include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "UMCPHandler_SetMaterialExpressionProperty.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialExpressionProperty : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Optional, Description="Material name or package path (specify this or materialFunction)"))
FString Material;
UPROPERTY(meta=(Optional, Description="Material function name or package path (specify this or material)"))
FString MaterialFunction;
UPROPERTY(meta=(Description="Expression node name (from FormatName)"))
FString Node;
virtual FString GetDescription() const override
{
return TEXT("Set the value or properties on a material expression node. "
"The 'value' field in the JSON payload provides the new value, whose format depends on the expression type.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
if (Material.IsEmpty() && MaterialFunction.IsEmpty())
{
Result.Append(TEXT("ERROR: Specify 'material' or 'materialFunction'\n"));
return;
}
if (!Json->HasField(TEXT("value")))
{
Result.Append(TEXT("ERROR: Missing required field: value\n"));
return;
}
// Load material or material function
UMaterial* MaterialObj = nullptr;
UMaterialFunction* MatFunc = nullptr;
if (!MaterialFunction.IsEmpty())
{
MCPAssets<UMaterialFunction> MFAssets;
if (!MFAssets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return;
MatFunc = MFAssets.Object();
}
else
{
MCPAssets<UMaterial> MatAssets;
if (!MatAssets.Exact(Material).Errors(Result).ENone().ETwo().Load()) return;
MaterialObj = MatAssets.Object();
}
if (MaterialObj) MCPUtils::EnsureMaterialGraph(MaterialObj);
UEdGraph* Graph = MaterialObj ? (UEdGraph*)MaterialObj->MaterialGraph : (MatFunc ? MatFunc->MaterialGraph : nullptr);
if (!Graph)
{
Result.Appendf(TEXT("ERROR: No material graph found\n"));
return;
}
// Find the node by name using Identifies
UMaterialGraphNode* TargetMatNode = nullptr;
for (UEdGraphNode* GraphNode : Graph->Nodes)
{
if (!GraphNode) continue;
if (!MCPUtils::Identifies(Node, GraphNode)) continue;
TargetMatNode = Cast<UMaterialGraphNode>(GraphNode);
if (TargetMatNode) break;
}
if (!TargetMatNode)
{
Result.Appendf(TEXT("ERROR: Node '%s' not found in material graph\n"), *Node);
return;
}
UMaterialExpression* Expr = TargetMatNode->MaterialExpression;
if (!Expr)
{
Result.Appendf(TEXT("ERROR: Node '%s' has no material expression\n"), *MCPUtils::FormatName(TargetMatNode));
return;
}
UObject* Asset = MaterialObj ? (UObject*)MaterialObj : (UObject*)MatFunc;
Asset->PreEditChange(nullptr);
FString SetResult;
if (!ApplyValue(Expr, Json, Result, SetResult))
{
Asset->PostEditChange();
return;
}
Asset->PostEditChange();
Asset->MarkPackageDirty();
bool bSaved = MaterialObj ? MCPUtils::SaveMaterialPackage(MaterialObj) : MCPUtils::SaveGenericPackage(MatFunc);
Result.Appendf(TEXT("%s = %s"), *MCPUtils::FormatName(Expr), *SetResult);
if (!bSaved) Result.Append(TEXT(" (save failed)"));
Result.Append(TEXT("\n"));
}
private:
// Apply the value from JSON to the expression. Returns false on error (with message in Result).
// On success, fills SetResult with a human-readable summary of the new value.
bool ApplyValue(UMaterialExpression* Expr, const FJsonObject* Json, FStringBuilderBase& Result, FString& SetResult)
{
if (auto* E = Cast<UMaterialExpressionConstant>(Expr))
{
double Value = Json->GetNumberField(TEXT("value"));
E->R = (float)Value;
SetResult = FString::Printf(TEXT("%g"), Value);
return true;
}
if (auto* E = Cast<UMaterialExpressionConstant3Vector>(Expr))
{
FLinearColor C;
if (!ParseColorValue(Json, C, false, Result)) return false;
E->Constant = C;
SetResult = FString::Printf(TEXT("(%.3f, %.3f, %.3f)"), C.R, C.G, C.B);
return true;
}
if (auto* E = Cast<UMaterialExpressionConstant4Vector>(Expr))
{
FLinearColor C;
if (!ParseColorValue(Json, C, true, Result)) return false;
E->Constant = C;
SetResult = FString::Printf(TEXT("(%.3f, %.3f, %.3f, %.3f)"), C.R, C.G, C.B, C.A);
return true;
}
if (auto* E = Cast<UMaterialExpressionScalarParameter>(Expr))
{
double Value = Json->GetNumberField(TEXT("value"));
E->DefaultValue = (float)Value;
SetResult = FString::Printf(TEXT("%g"), Value);
ApplyParameterName(E, Json);
return true;
}
if (auto* E = Cast<UMaterialExpressionVectorParameter>(Expr))
{
FLinearColor C;
if (!ParseColorValue(Json, C, true, Result)) return false;
E->DefaultValue = C;
SetResult = FString::Printf(TEXT("(%.3f, %.3f, %.3f, %.3f)"), C.R, C.G, C.B, C.A);
ApplyParameterName(E, Json);
return true;
}
if (auto* E = Cast<UMaterialExpressionTextureCoordinate>(Expr))
{
const TSharedPtr<FJsonObject>* ValueObj = nullptr;
if (!Json->TryGetObjectField(TEXT("value"), ValueObj) || !ValueObj || !(*ValueObj).IsValid())
{
Result.Append(TEXT("ERROR: TextureCoordinate requires value as {coordinateIndex, uTiling, vTiling}\n"));
return false;
}
double CoordIndex = 0, UTiling = 1, VTiling = 1;
(*ValueObj)->TryGetNumberField(TEXT("coordinateIndex"), CoordIndex);
(*ValueObj)->TryGetNumberField(TEXT("uTiling"), UTiling);
(*ValueObj)->TryGetNumberField(TEXT("vTiling"), VTiling);
E->CoordinateIndex = (int32)CoordIndex;
E->UTiling = (float)UTiling;
E->VTiling = (float)VTiling;
SetResult = FString::Printf(TEXT("index=%d uTiling=%g vTiling=%g"), (int32)CoordIndex, UTiling, VTiling);
return true;
}
if (auto* E = Cast<UMaterialExpressionCustom>(Expr))
{
FString Code;
if (Json->TryGetStringField(TEXT("code"), Code))
{
E->Code = Code;
}
else if (Json->HasField(TEXT("value")))
{
FString ValueStr = Json->GetStringField(TEXT("value"));
if (!ValueStr.IsEmpty()) E->Code = ValueStr;
}
SetResult = FString::Printf(TEXT("code: %d chars"), E->Code.Len());
FString OutputTypeStr;
if (Json->TryGetStringField(TEXT("outputType"), OutputTypeStr) && !OutputTypeStr.IsEmpty())
{
ECustomMaterialOutputType OutType;
if (MCPUtils::StringToEnum(OutputTypeStr, OutType, MCPErrorCallback(Result)))
E->OutputType = OutType;
}
return true;
}
if (auto* E = Cast<UMaterialExpressionComponentMask>(Expr))
{
const TSharedPtr<FJsonObject>* ValueObj = nullptr;
if (!Json->TryGetObjectField(TEXT("value"), ValueObj) || !ValueObj || !(*ValueObj).IsValid())
{
Result.Append(TEXT("ERROR: ComponentMask requires value as {r, g, b, a} (booleans)\n"));
return false;
}
bool bR = false, bG = false, bB = false, bA = false;
(*ValueObj)->TryGetBoolField(TEXT("r"), bR);
(*ValueObj)->TryGetBoolField(TEXT("g"), bG);
(*ValueObj)->TryGetBoolField(TEXT("b"), bB);
(*ValueObj)->TryGetBoolField(TEXT("a"), bA);
E->R = bR ? 1 : 0;
E->G = bG ? 1 : 0;
E->B = bB ? 1 : 0;
E->A = bA ? 1 : 0;
SetResult = FString::Printf(TEXT("R=%s G=%s B=%s A=%s"),
bR ? TEXT("true") : TEXT("false"),
bG ? TEXT("true") : TEXT("false"),
bB ? TEXT("true") : TEXT("false"),
bA ? TEXT("true") : TEXT("false"));
return true;
}
Result.Appendf(TEXT("ERROR: Expression type '%s' does not support value setting. Supported: "
"Constant, Constant3Vector, Constant4Vector, ScalarParameter, VectorParameter, "
"TextureCoordinate, Custom, ComponentMask\n"),
*Expr->GetClass()->GetName());
return false;
}
// Parse {r, g, b[, a]} from the "value" JSON field.
bool ParseColorValue(const FJsonObject* Json, FLinearColor& OutColor, bool bHasAlpha, FStringBuilderBase& Result)
{
const TSharedPtr<FJsonObject>* ValueObj = nullptr;
if (!Json->TryGetObjectField(TEXT("value"), ValueObj) || !ValueObj || !(*ValueObj).IsValid())
{
Result.Appendf(TEXT("ERROR: requires value as {r, g, b%s}\n"), bHasAlpha ? TEXT(", a") : TEXT(""));
return false;
}
double R = 0, G = 0, B = 0, A = 1;
(*ValueObj)->TryGetNumberField(TEXT("r"), R);
(*ValueObj)->TryGetNumberField(TEXT("g"), G);
(*ValueObj)->TryGetNumberField(TEXT("b"), B);
if (bHasAlpha) (*ValueObj)->TryGetNumberField(TEXT("a"), A);
OutColor = FLinearColor((float)R, (float)G, (float)B, (float)A);
return true;
}
// If the JSON has a "parameterName" field, apply it to a parameter expression.
void ApplyParameterName(UMaterialExpressionParameter* Param, const FJsonObject* Json)
{
FString ParamName;
if (Json->TryGetStringField(TEXT("parameterName"), ParamName) && !ParamName.IsEmpty())
Param->ParameterName = FName(*ParamName);
}
};

View File

@@ -1,72 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "StructUtils/UserDefinedStruct.h"
#include "UserDefinedStructure/UserDefinedStructEditorData.h"
#include "UMCPHandler_AddStructField.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddStructField : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Package path of the struct asset"))
FString Struct;
UPROPERTY(meta=(Description="Name for the new field"))
FString Name;
UPROPERTY(meta=(Description="Type for the new field (e.g. 'int32', 'FString', 'FVector')"))
FString Type;
virtual FString GetDescription() const override
{
return TEXT("Add a new field to a UserDefinedStruct asset.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
// Find the struct
MCPFetcher F(Result);
UUserDefinedStruct* S = F.Walk(Struct).Cast<UUserDefinedStruct>();
if (!S) return;
// Resolve type
FEdGraphPinType PinType;
if (!MCPUtils::ResolveTypeFromString(Type, PinType, Result))
return;
// Snapshot existing GUIDs so we can find the newly added one
TSet<FGuid> ExistingGuids;
for (const FStructVariableDescription& Var : FStructureEditorUtils::GetVarDesc(S))
ExistingGuids.Add(Var.VarGuid);
if (!FStructureEditorUtils::AddVariable(S, PinType))
{
Result.Append(TEXT("ERROR: Failed to add field to struct.\n"));
return;
}
// Find the new variable by diffing GUID sets and rename it
for (const FStructVariableDescription& Var : FStructureEditorUtils::GetVarDesc(S))
{
if (!ExistingGuids.Contains(Var.VarGuid))
{
FStructureEditorUtils::RenameVariable(S, Var.VarGuid, Name);
break;
}
}
MCPUtils::SaveGenericPackage(S);
Result.Appendf(TEXT("Added field: %s %s\n"), *Type, *Name);
}
};

View File

@@ -1,207 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraphSchema_K2.h"
#include "K2Node_BreakStruct.h"
#include "K2Node_MakeStruct.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_ChangeStructNodeType.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ChangeStructNodeType : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Path to the node, e.g. /Game/Foo,graph:EventGraph,node:BreakVector"))
FString Node;
UPROPERTY(meta=(Description="New struct type name (e.g. 'Vector', 'FVector', 'Rotator')"))
FString NewType;
virtual FString GetDescription() const override
{
return TEXT("Change the struct type on a BreakStruct or MakeStruct node. "
"Attempts to reconnect matching pins after the type change.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPFetcher F(Result);
UEdGraphNode* FoundNode = F.Walk(Node).Cast<UEdGraphNode>();
if (!FoundNode) return;
// Determine what kind of struct node this is
UK2Node_BreakStruct* BreakNode = Cast<UK2Node_BreakStruct>(FoundNode);
UK2Node_MakeStruct* MakeNode = Cast<UK2Node_MakeStruct>(FoundNode);
if (!BreakNode && !MakeNode)
{
MCPErrorCallback(Result).SetError(FString::Printf(
TEXT("Node %s is not a BreakStruct or MakeStruct (class: %s)"),
*MCPUtils::FormatName(FoundNode), *MCPUtils::FormatName(FoundNode->GetClass())));
return;
}
// Find the new struct type
UScriptStruct* NewStruct = FindStructByName(NewType);
if (!NewStruct)
{
MCPErrorCallback(Result).SetError(FString::Printf(TEXT("Struct type '%s' not found"), *NewType));
return;
}
UEdGraph* Graph = FoundNode->GetGraph();
const UEdGraphSchema* Schema = Graph ? Graph->GetSchema() : nullptr;
if (!Schema)
{
MCPErrorCallback(Result).SetError(TEXT("Graph schema not found"));
return;
}
// Remember existing connections keyed by property base name
struct FPinConnection
{
EEdGraphPinDirection Direction;
TArray<UEdGraphPin*> LinkedPins;
};
TMap<FString, FPinConnection> ConnectionsByBaseName;
for (UEdGraphPin* Pin : FoundNode->Pins)
{
if (!Pin || Pin->LinkedTo.Num() == 0) continue;
if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec) continue;
FString BaseName = ExtractPropertyBaseName(Pin->PinName.ToString());
FPinConnection& Conn = ConnectionsByBaseName.FindOrAdd(BaseName);
Conn.Direction = Pin->Direction;
Conn.LinkedPins = Pin->LinkedTo;
}
// Change the struct type and reconstruct
if (BreakNode) BreakNode->StructType = NewStruct;
else MakeNode->StructType = NewStruct;
FoundNode->BreakAllNodeLinks();
Schema->ReconstructNode(*FoundNode);
// Reconnect pins by matching property base names
int32 Reconnected = 0;
int32 Failed = 0;
for (auto& Pair : ConnectionsByBaseName)
{
const FString& BaseName = Pair.Key;
const FPinConnection& OldConn = Pair.Value;
UEdGraphPin* NewPin = FindMatchingPin(FoundNode, BaseName, OldConn.Direction, NewStruct);
if (NewPin)
{
for (UEdGraphPin* Target : OldConn.LinkedPins)
{
if (Schema->TryCreateConnection(NewPin, Target))
Reconnected++;
else
Failed++;
}
}
else
{
Failed += OldConn.LinkedPins.Num();
}
}
// Get the owning blueprint and mark modified
UBlueprint* BP = FBlueprintEditorUtils::FindBlueprintForGraph(Graph);
if (BP) FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(BP);
// Output
Result.Appendf(TEXT("Changed to %s\n"), *MCPUtils::FormatName(NewStruct));
Result.Appendf(TEXT("Reconnected: %d\n"), Reconnected);
if (Failed > 0)
Result.Appendf(TEXT("Failed: %d\n"), Failed);
}
private:
// Find a UScriptStruct by name, trying with and without F prefix.
static UScriptStruct* FindStructByName(const FString& TypeName)
{
// Try stripping F prefix first (Unreal stores structs without it)
FString InternalName = TypeName;
if (TypeName.StartsWith(TEXT("F")))
InternalName = TypeName.Mid(1);
UScriptStruct* Found = FindFirstObject<UScriptStruct>(*InternalName);
if (Found) return Found;
// Try the original name
Found = FindFirstObject<UScriptStruct>(*TypeName);
if (Found) return Found;
// Fallback: iterate all UScriptStructs and use Identifies
for (TObjectIterator<UScriptStruct> It; It; ++It)
{
if (MCPUtils::Identifies(TypeName, *It))
return *It;
}
return nullptr;
}
// Extract the property base name from a pin name, stripping the GUID
// and numeric index suffixes that Unreal appends.
static FString ExtractPropertyBaseName(const FString& PinName)
{
int32 LastUnderscore;
if (!PinName.FindLastChar(TEXT('_'), LastUnderscore) || LastUnderscore <= 0)
return PinName;
FString Suffix = PinName.Mid(LastUnderscore + 1);
if (Suffix.Len() != 32)
return PinName;
FString WithoutGuid = PinName.Left(LastUnderscore);
int32 SecondUnderscore;
if (!WithoutGuid.FindLastChar(TEXT('_'), SecondUnderscore) || SecondUnderscore <= 0)
return WithoutGuid;
FString IndexStr = WithoutGuid.Mid(SecondUnderscore + 1);
if (IndexStr.IsNumeric())
return WithoutGuid.Left(SecondUnderscore);
return WithoutGuid;
}
// Find a pin on the node matching the given base name and direction.
// Falls back to matching the struct-typed pin if no name match is found.
static UEdGraphPin* FindMatchingPin(UEdGraphNode* Node, const FString& BaseName,
EEdGraphPinDirection Direction, UScriptStruct* NewStruct)
{
for (UEdGraphPin* Pin : Node->Pins)
{
if (!Pin || Pin->Direction != Direction) continue;
FString NewBaseName = ExtractPropertyBaseName(Pin->PinName.ToString());
if (NewBaseName.Equals(BaseName, ESearchCase::IgnoreCase))
return Pin;
}
// Fallback: match the single struct-typed pin
for (UEdGraphPin* Pin : Node->Pins)
{
if (!Pin || Pin->Direction != Direction) continue;
if (Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Struct &&
Pin->PinType.PinSubCategoryObject == NewStruct)
return Pin;
}
return nullptr;
}
};

View File

@@ -1,84 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "EdGraph/EdGraphPin.h"
#include "UMCPHandler_CheckPinConnectionCompatibility.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// Pre-flight check: can two pins be connected?
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CheckPinConnectionCompatibility : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Path to the source pin, e.g. /Game/Foo,graph:EventGraph,node:MyNode,pin:Output"))
FString SourcePin;
UPROPERTY(meta=(Description="Path to the target pin, e.g. /Game/Foo,graph:EventGraph,node:OtherNode,pin:Input"))
FString TargetPin;
virtual FString GetDescription() const override
{
return TEXT("Check whether two pins can be connected, and what kind of connection would result.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPFetcher FS(Result);
UEdGraphPin* SrcPin = FS.Walk(SourcePin).Cast<UEdGraphPin>();
if (!SrcPin) return;
MCPFetcher FT(Result);
UEdGraphPin* TgtPin = FT.Walk(TargetPin).Cast<UEdGraphPin>();
if (!TgtPin) return;
const UEdGraphSchema* Schema = SrcPin->GetOwningNode()->GetGraph()->GetSchema();
const FPinConnectionResponse Response = Schema->CanCreateConnection(SrcPin, TgtPin);
bool bCompatible = (Response.Response != ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW);
// Decode the response type
const TCHAR* ResponseType;
switch (Response.Response)
{
case ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE:
ResponseType = TEXT("direct");
break;
case ECanCreateConnectionResponse::CONNECT_RESPONSE_BREAK_OTHERS_A:
ResponseType = TEXT("break-source-connections");
break;
case ECanCreateConnectionResponse::CONNECT_RESPONSE_BREAK_OTHERS_B:
ResponseType = TEXT("break-target-connections");
break;
case ECanCreateConnectionResponse::CONNECT_RESPONSE_BREAK_OTHERS_AB:
ResponseType = TEXT("break-both-connections");
break;
case ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE_WITH_CONVERSION_NODE:
ResponseType = TEXT("requires-conversion");
break;
case ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE_WITH_PROMOTION:
ResponseType = TEXT("requires-promotion");
break;
case ECanCreateConnectionResponse::CONNECT_RESPONSE_DISALLOW:
default:
ResponseType = TEXT("disallowed");
break;
}
Result.Appendf(TEXT("Compatible: %s\n"), bCompatible ? TEXT("yes") : TEXT("no"));
Result.Appendf(TEXT("ConnectionType: %s\n"), ResponseType);
if (!Response.Message.IsEmpty())
Result.Appendf(TEXT("Message: %s\n"), *Response.Message.ToString());
Result.Appendf(TEXT("SourcePinType: %s\n"), *MCPUtils::FormatPinType(SrcPin));
Result.Appendf(TEXT("TargetPinType: %s\n"), *MCPUtils::FormatPinType(TgtPin));
}
};

View File

@@ -1,71 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Materials/Material.h"
#include "Materials/MaterialInstanceConstant.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "UMCPHandler_FindMaterialReferences.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_FindMaterialReferences : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Material or MaterialInstance name or package path"))
FString Material;
virtual FString GetDescription() const override
{
return TEXT("Find all assets that reference a given material or material instance.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
// Find the material asset (searching both Material and MaterialInstance)
MCPAssets<UMaterial> Assets;
Assets.Scan<UMaterial>().Scan<UMaterialInstanceConstant>();
if (!Assets.Exact(Material).Errors(Result).ENone().ETwo().Info()) return;
FString PackagePath = Assets.OneData().PackageName.ToString();
IAssetRegistry& Registry = *IAssetRegistry::Get();
TArray<FName> Referencers;
Registry.GetReferencers(FName(*PackagePath), Referencers);
// Filter out self-references and classify each referencer
int32 Count = 0;
for (const FName& Ref : Referencers)
{
FString RefStr = Ref.ToString();
if (RefStr == PackagePath) continue;
TArray<FAssetData> RefAssets;
Registry.GetAssetsByPackageName(Ref, RefAssets);
if (RefAssets.Num() > 0)
{
Result.Appendf(TEXT("%s %s\n"),
*MCPUtils::FormatName(RefAssets[0].GetClass()),
*RefStr);
}
else
{
Result.Appendf(TEXT("Unknown %s\n"), *RefStr);
}
Count++;
}
if (Count == 0)
{
Result.Append(TEXT("No referencers found.\n"));
}
}
};

View File

@@ -1,75 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "StructUtils/UserDefinedStruct.h"
#include "UserDefinedStructure/UserDefinedStructEditorData.h"
#include "UMCPHandler_RemoveStructField.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveStructField : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Struct name or package path"))
FString Struct;
UPROPERTY(meta=(Description="Name of the field to remove"))
FString FieldName;
virtual FString GetDescription() const override
{
return TEXT("Remove a field from a UserDefinedStruct asset.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
MCPFetcher F(Result);
UUserDefinedStruct* S = F.Walk(Struct).Cast<UUserDefinedStruct>();
if (!S) return;
// Find the field GUID by name
FGuid TargetGuid;
bool bFound = false;
for (const FStructVariableDescription& Var : FStructureEditorUtils::GetVarDesc(S))
{
if (Var.FriendlyName.Equals(FieldName, ESearchCase::IgnoreCase) ||
Var.VarName.ToString().Equals(FieldName, ESearchCase::IgnoreCase))
{
TargetGuid = Var.VarGuid;
bFound = true;
break;
}
}
if (!bFound)
{
Result.Appendf(TEXT("ERROR: Field '%s' not found in %s.\nAvailable fields:\n"),
*FieldName, *MCPUtils::FormatName(S));
for (const FStructVariableDescription& Var : FStructureEditorUtils::GetVarDesc(S))
{
Result.Appendf(TEXT(" %s\n"), *Var.FriendlyName);
}
return;
}
if (!FStructureEditorUtils::RemoveVariable(S, TargetGuid))
{
Result.Appendf(TEXT("ERROR: Failed to remove field '%s'."), *FieldName);
return;
}
bool bSaved = MCPUtils::SaveGenericPackage(S);
Result.Appendf(TEXT("Removed field %s from %s.%s\n"),
*FieldName, *MCPUtils::FormatName(S),
bSaved ? TEXT("") : TEXT(" WARNING: save failed."));
}
};

View File

@@ -1,162 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraphSchema_K2.h"
#include "K2Node_CallFunction.h"
#include "Kismet2/BlueprintEditorUtils.h"
#include "UMCPHandler_ReplaceFunctionCallsInBlueprint.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ReplaceFunctionCallsInBlueprint : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Blueprint name or package path"))
FString Blueprint;
UPROPERTY(meta=(Description="Old class name to match"))
FString OldClass;
UPROPERTY(meta=(Description="New class name to redirect to"))
FString NewClass;
UPROPERTY(meta=(Optional, Description="If true, report what would change without modifying"))
bool DryRun = false;
virtual FString GetDescription() const override
{
return TEXT("Redirect function call nodes from one class to another. "
"Supports dry-run to preview impact before applying.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
// Load Blueprint
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
UBlueprint* BP = Assets.Object();
// Find the new class
UClass* NewClassPtr = MCPUtils::FindClassByName(NewClass);
if (!NewClassPtr)
{
Result.Appendf(TEXT("ERROR: Could not find class '%s'\n"), *NewClass);
return;
}
int32 ReplacedCount = 0;
for (UK2Node_CallFunction* CallNode : MCPUtils::AllNodes<UK2Node_CallFunction>(BP))
{
UClass* ParentClass = CallNode->FunctionReference.GetMemberParentClass();
if (!ParentClass) continue;
if (!MCPUtils::Identifies(OldClass, ParentClass)) continue;
FName FuncName = CallNode->FunctionReference.GetMemberName();
// Find the matching function in the new class
UFunction* NewFunc = NewClassPtr->FindFunctionByName(FuncName);
if (!NewFunc)
{
Result.Appendf(TEXT("WARNING: Function '%s' not found in %s, skipping %s\n"),
*FuncName.ToString(), *MCPUtils::FormatName(NewClassPtr), *MCPUtils::FormatName(CallNode));
continue;
}
if (DryRun)
{
ReplacedCount++;
// Check which connected pins might not exist in the new function
for (UEdGraphPin* Pin : CallNode->Pins)
{
if (!Pin || Pin->LinkedTo.Num() == 0) continue;
bool bPinExistsInNew = false;
if (Pin->PinName == UEdGraphSchema_K2::PN_Execute ||
Pin->PinName == UEdGraphSchema_K2::PN_Then ||
Pin->PinName == UEdGraphSchema_K2::PN_Self ||
Pin->PinName == UEdGraphSchema_K2::PN_ReturnValue)
{
bPinExistsInNew = true;
}
else
{
for (TFieldIterator<FProperty> PropIt(NewFunc); PropIt; ++PropIt)
{
if (PropIt->GetFName() == Pin->PinName)
{
bPinExistsInNew = true;
break;
}
}
}
if (!bPinExistsInNew)
{
Result.Appendf(TEXT("AT RISK: %s pin %s -> %s\n"),
*MCPUtils::FormatName(CallNode), *MCPUtils::FormatName(Pin),
*MCPUtils::FormatName(Pin->LinkedTo[0]));
}
}
}
else
{
// Record existing pin connections before replacement
TMap<FName, TArray<UEdGraphPin*>> OldPinConnections;
for (UEdGraphPin* Pin : CallNode->Pins)
{
if (Pin->LinkedTo.Num() > 0)
{
OldPinConnections.Add(Pin->PinName, Pin->LinkedTo);
}
}
// Replace the function reference
CallNode->SetFromFunction(NewFunc);
ReplacedCount++;
// Report lost connections
for (auto& Pair : OldPinConnections)
{
UEdGraphPin* NewPin = CallNode->FindPin(Pair.Key);
for (UEdGraphPin* OldLinked : Pair.Value)
{
if (!OldLinked || !OldLinked->GetOwningNode()) continue;
bool bStillConnected = NewPin && NewPin->LinkedTo.Contains(OldLinked);
if (!bStillConnected)
{
Result.Appendf(TEXT("LOST: %s pin %s was connected to %s\n"),
*MCPUtils::FormatName(CallNode), *Pair.Key.ToString(),
*MCPUtils::FormatName(OldLinked));
}
}
}
}
}
if (DryRun)
{
Result.Appendf(TEXT("Dry run: %d node(s) would be replaced\n"), ReplacedCount);
return;
}
if (ReplacedCount > 0)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
Result.Appendf(TEXT("Replaced %d node(s)\n"), ReplacedCount);
}
};

View File

@@ -1,229 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Engine/World.h"
#include "Engine/Level.h"
#include "Engine/LevelScriptBlueprint.h"
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "K2Node_CallFunction.h"
#include "K2Node_Event.h"
#include "K2Node_CustomEvent.h"
#include "K2Node_VariableGet.h"
#include "K2Node_VariableSet.h"
#include "K2Node_BreakStruct.h"
#include "K2Node_MakeStruct.h"
#include "K2Node_FunctionEntry.h"
#include "K2Node_EditablePinBase.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "UMCPHandler_SearchTypeUsageInBlueprints.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ============================================================
// HandleSearchByType — find all usages of a type across blueprints
// ============================================================
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchTypeUsageInBlueprints : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Type name to search for (e.g. 'FVector', 'MyStruct'). F/E/U prefix is stripped for matching."))
FString TypeName;
UPROPERTY(meta=(Optional, Description="Filter to blueprints whose name or path contains this substring"))
FString Query;
UPROPERTY(meta=(Optional, Description="Maximum number of results to return (default 200, max 500)"))
int32 MaxResults = 0;
virtual FString GetDescription() const override
{
return TEXT("Search all Blueprints for usages of a specific type in variables, function parameters, struct nodes, and pin connections.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
FString DecodedTypeName = MCPUtils::UrlDecode(TypeName);
FString FilterStr = Query.IsEmpty() ? FString() : MCPUtils::UrlDecode(Query);
int32 EffectiveMaxResults = (MaxResults > 0) ? FMath::Clamp(MaxResults, 1, 500) : 200;
// Strip F/E/U prefix for comparison
FString TypeNameNoPrefix = DecodedTypeName;
if (TypeNameNoPrefix.StartsWith(TEXT("F")) || TypeNameNoPrefix.StartsWith(TEXT("E")) || TypeNameNoPrefix.StartsWith(TEXT("U")))
{
TypeNameNoPrefix = TypeNameNoPrefix.Mid(1);
}
auto MatchesType = [&DecodedTypeName, &TypeNameNoPrefix](const FString& TestType) -> bool
{
return TestType.Equals(DecodedTypeName, ESearchCase::IgnoreCase) ||
TestType.Equals(TypeNameNoPrefix, ESearchCase::IgnoreCase);
};
int32 ResultCount = 0;
// Helper: get subtype name from a pin type
auto GetSubtype = [](const FEdGraphPinType& PinType) -> FString
{
if (PinType.PinSubCategoryObject.IsValid())
return PinType.PinSubCategoryObject->GetName();
return FString();
};
// Helper: check if a pin type matches
auto PinTypeMatches = [&](const FEdGraphPinType& PinType) -> bool
{
return MatchesType(GetSubtype(PinType)) || MatchesType(PinType.PinCategory.ToString());
};
// Lambda that searches a single Blueprint for type usages
auto SearchOneBlueprint = [&](UBlueprint* BP, bool bIsLevel)
{
FString BPName = MCPUtils::FormatName(BP);
// Check variables
for (const FBPVariableDescription& Var : BP->NewVariables)
{
if (ResultCount >= EffectiveMaxResults) return;
if (!PinTypeMatches(Var.VarType)) continue;
Result.Appendf(TEXT("variable %s in %s: %s %s\n"),
*MCPUtils::FormatName(Var), *BPName,
*Var.VarType.PinCategory.ToString(), *GetSubtype(Var.VarType));
ResultCount++;
}
// Check graphs for function/event params, struct nodes, and pin connections
for (UEdGraphNode* Node : MCPUtils::AllNodes(BP))
{
if (ResultCount >= EffectiveMaxResults) return;
// Check FunctionEntry parameters
if (auto* FuncEntry = Cast<UK2Node_FunctionEntry>(Node))
{
for (const TSharedPtr<FUserPinInfo>& PinInfo : FuncEntry->UserDefinedPins)
{
if (!PinInfo.IsValid()) continue;
if (!PinTypeMatches(PinInfo->PinType)) continue;
Result.Appendf(TEXT("func-param %s.%s in %s: %s %s\n"),
*MCPUtils::FormatName(Node->GetGraph()), *PinInfo->PinName.ToString(),
*BPName,
*PinInfo->PinType.PinCategory.ToString(), *GetSubtype(PinInfo->PinType));
ResultCount++;
}
}
else if (auto* CustomEvent = Cast<UK2Node_CustomEvent>(Node))
{
for (const TSharedPtr<FUserPinInfo>& PinInfo : CustomEvent->UserDefinedPins)
{
if (!PinInfo.IsValid()) continue;
if (!PinTypeMatches(PinInfo->PinType)) continue;
Result.Appendf(TEXT("event-param %s.%s in %s: %s %s\n"),
*MCPUtils::FormatName(Node), *PinInfo->PinName.ToString(),
*BPName,
*PinInfo->PinType.PinCategory.ToString(), *GetSubtype(PinInfo->PinType));
ResultCount++;
}
}
// Check Break/Make struct nodes
else if (auto* BreakNode = Cast<UK2Node_BreakStruct>(Node))
{
if (BreakNode->StructType && MatchesType(BreakNode->StructType->GetName()))
{
Result.Appendf(TEXT("break-struct %s in %s graph %s\n"),
*BreakNode->StructType->GetName(), *BPName,
*MCPUtils::FormatName(Node->GetGraph()));
ResultCount++;
}
}
else if (auto* MakeNode = Cast<UK2Node_MakeStruct>(Node))
{
if (MakeNode->StructType && MatchesType(MakeNode->StructType->GetName()))
{
Result.Appendf(TEXT("make-struct %s in %s graph %s\n"),
*MakeNode->StructType->GetName(), *BPName,
*MCPUtils::FormatName(Node->GetGraph()));
ResultCount++;
}
}
// Check pin connections carrying the type
for (UEdGraphPin* Pin : Node->Pins)
{
if (!Pin || Pin->bHidden || ResultCount >= EffectiveMaxResults) continue;
if (Pin->LinkedTo.Num() == 0) continue;
if (!PinTypeMatches(Pin->PinType)) continue;
Result.Appendf(TEXT("pin %s.%s in %s graph %s: %s %s (%d connections)\n"),
*MCPUtils::FormatName(Node), *MCPUtils::FormatName(Pin),
*BPName, *MCPUtils::FormatName(Node->GetGraph()),
*Pin->PinType.PinCategory.ToString(), *GetSubtype(Pin->PinType),
Pin->LinkedTo.Num());
ResultCount++;
}
}
};
MCPAssets<UBlueprint> AllBlueprints;
AllBlueprints.Info();
MCPAssets<UWorld> AllWorlds;
AllWorlds.Info();
// Search regular blueprints
for (const FAssetData& Asset : AllBlueprints.AllData())
{
if (ResultCount >= EffectiveMaxResults) break;
FString AssetPath = Asset.PackageName.ToString();
FString AssetName = Asset.AssetName.ToString();
if (!FilterStr.IsEmpty() && !AssetName.Contains(FilterStr, ESearchCase::IgnoreCase) &&
!AssetPath.Contains(FilterStr, ESearchCase::IgnoreCase))
{
continue;
}
UBlueprint* BP = Cast<UBlueprint>(const_cast<FAssetData&>(Asset).GetAsset());
if (!BP) continue;
SearchOneBlueprint(BP, false);
}
// Search level blueprints from maps
for (const FAssetData& MapAsset : AllWorlds.AllData())
{
if (ResultCount >= EffectiveMaxResults) break;
FString AssetPath = MapAsset.PackageName.ToString();
FString MapName = MapAsset.AssetName.ToString();
if (!FilterStr.IsEmpty() && !MapName.Contains(FilterStr, ESearchCase::IgnoreCase) &&
!AssetPath.Contains(FilterStr, ESearchCase::IgnoreCase))
{
continue;
}
UWorld* World = Cast<UWorld>(MapAsset.GetAsset());
if (!World || !World->PersistentLevel) continue;
ULevelScriptBlueprint* LevelBP = World->PersistentLevel->GetLevelScriptBlueprint(false);
if (!LevelBP) continue;
SearchOneBlueprint(LevelBP, true);
}
Result.Appendf(TEXT("\n%d results\n"), ResultCount);
}
};

View File

@@ -1,162 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPAssetFinder.h"
#include "MCPFetcher.h"
#include "MCPUtils.h"
#include "Engine/Blueprint.h"
#include "Kismet2/KismetEditorUtilities.h"
#include "UObject/UObjectIterator.h"
#include "UMCPHandler_SetClassDefaultValue.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetClassDefaultValue : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="Blueprint name or package path"))
FString Blueprint;
UPROPERTY(meta=(Description="Property name on the Class Default Object"))
FString Property;
UPROPERTY(meta=(Description="New value (parsed according to property type)"))
FString Value;
virtual FString GetDescription() const override
{
return TEXT("Set a default property value on a Blueprint's Class Default Object. "
"Handles class references, object references, and simple types.");
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{
// Load Blueprint
MCPAssets<UBlueprint> Assets;
if (!Assets.Exact(Blueprint).Errors(Result).ENone().ETwo().Load()) return;
UBlueprint* BP = Assets.Object();
if (!BP->GeneratedClass)
{
Result.Append(TEXT("Error: Blueprint has no GeneratedClass\n"));
return;
}
UObject* CDO = BP->GeneratedClass->GetDefaultObject();
if (!CDO)
{
Result.Append(TEXT("Error: Could not get Class Default Object\n"));
return;
}
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(*Property);
if (!Prop)
{
Result.Appendf(TEXT("Error: Property '%s' not found on %s\n"), *Property, *MCPUtils::FormatName(BP));
return;
}
FString OldValue;
Prop->ExportTextItem_Direct(OldValue, Prop->ContainerPtrToValuePtr<void>(CDO), nullptr, CDO, PPF_None);
FString ActualNewValue;
// Handle class/soft-class properties (TSubclassOf, TSoftClassPtr)
FClassProperty* ClassProp = CastField<FClassProperty>(Prop);
FSoftClassProperty* SoftClassProp = CastField<FSoftClassProperty>(Prop);
if (ClassProp || SoftClassProp)
{
UClass* ResolvedClass = ResolveClass(Value, Result);
if (!ResolvedClass) return;
// Validate meta class compatibility
if (ClassProp)
{
UClass* MetaClass = ClassProp->MetaClass;
if (MetaClass && !ResolvedClass->IsChildOf(MetaClass))
{
Result.Appendf(TEXT("Error: %s is not a subclass of %s (required by property '%s')\n"),
*MCPUtils::FormatName(ResolvedClass), *MCPUtils::FormatName(MetaClass), *Property);
return;
}
ClassProp->SetPropertyValue_InContainer(CDO, ResolvedClass);
}
else
{
FSoftObjectPtr SoftPtr(ResolvedClass);
SoftClassProp->SetPropertyValue_InContainer(CDO, SoftPtr);
}
ActualNewValue = MCPUtils::FormatName(ResolvedClass);
}
// Handle object properties (TObjectPtr, UObject*)
else if (FObjectProperty* ObjProp = CastField<FObjectProperty>(Prop))
{
MCPAssets<UBlueprint> ValueAssets;
if (!ValueAssets.Exact(Value).AllContent().Errors(Result).ENone().ETwo().Load()) return;
UObject* ResolvedObj = nullptr;
if (ValueAssets.Object()->GeneratedClass)
ResolvedObj = ValueAssets.Object()->GeneratedClass->GetDefaultObject();
if (!ResolvedObj)
{
Result.Appendf(TEXT("Error: Could not resolve '%s' to an object\n"), *Value);
return;
}
ObjProp->SetPropertyValue_InContainer(CDO, ResolvedObj);
ActualNewValue = MCPUtils::FormatName(ValueAssets.Object());
}
// Handle simple types via ImportText
else
{
const TCHAR* ImportResult = Prop->ImportText_Direct(*Value, Prop->ContainerPtrToValuePtr<void>(CDO), CDO, PPF_None);
if (!ImportResult)
{
Result.Appendf(TEXT("Error: Failed to parse '%s' as %s for property '%s'\n"),
*Value, *Prop->GetCPPType(), *Property);
return;
}
Prop->ExportTextItem_Direct(ActualNewValue, Prop->ContainerPtrToValuePtr<void>(CDO), nullptr, CDO, PPF_None);
}
// Mark modified and save
CDO->MarkPackageDirty();
BP->Modify();
FKismetEditorUtilities::CompileBlueprint(BP);
bool bSaved = MCPUtils::SaveBlueprintPackage(BP);
Result.Appendf(TEXT("%s %s: %s -> %s\n"), *Prop->GetCPPType(), *Property, *OldValue, *ActualNewValue);
if (!bSaved)
Result.Append(TEXT("Warning: Save failed\n"));
}
private:
// Try to resolve a string to a UClass: first as a C++ class name, then as a Blueprint asset.
UClass* ResolveClass(const FString& ClassName, FStringBuilderBase& Result)
{
// Try as a C++ class name
for (TObjectIterator<UClass> It; It; ++It)
{
if (It->GetName() == ClassName || It->GetName() == ClassName + TEXT("_C"))
return *It;
}
// Try loading as a Blueprint asset
MCPAssets<UBlueprint> ValueAssets;
if (!ValueAssets.Exact(ClassName).AllContent().Errors(Result).ETwo().Load()) return nullptr;
if (!ValueAssets.Objects().IsEmpty() && ValueAssets.Object()->GeneratedClass)
return ValueAssets.Object()->GeneratedClass;
Result.Appendf(TEXT("Error: Could not resolve '%s' to a class\n"), *ClassName);
return nullptr;
}
};

View File

@@ -1,80 +0,0 @@
#include "Handlers/UMCPHandler_AddAnimStateToMachine.h"
#include "Handlers/UMCPHandler_AddAnimStateTransition.h"
#include "Handlers/UMCPHandler_AddBlueprintComponent.h"
#include "Handlers/UMCPHandler_AddBlueprintInterface.h"
#include "Handlers/UMCPHandler_AddBlueprintVariable.h"
#include "Handlers/UMCPHandler_AddEventDispatcher.h"
#include "Handlers/UMCPHandler_AddFunctionParameter.h"
#include "Handlers/UMCPHandler_AddStructField.h"
#include "Handlers/UMCPHandler_BackupAsset.h"
#include "Handlers/UMCPHandler_ChangeBlueprintVariableType.h"
#include "Handlers/UMCPHandler_ChangeFunctionParameterType.h"
#include "Handlers/UMCPHandler_ChangeStructNodeType.h"
#include "Handlers/UMCPHandler_CheckPinConnectionCompatibility.h"
#include "Handlers/UMCPHandler_CompileBlueprint.h"
#include "Handlers/UMCPHandler_CompileMaterial.h"
#include "Handlers/UMCPHandler_ConnectPins.h"
#include "Handlers/UMCPHandler_CreateAnimBlueprintAsset.h"
#include "Handlers/UMCPHandler_CreateBlendSpaceAsset.h"
#include "Handlers/UMCPHandler_CreateBlueprintAsset.h"
#include "Handlers/UMCPHandler_CreateBlueprintGraph.h"
#include "Handlers/UMCPHandler_CreateEnumAsset.h"
#include "Handlers/UMCPHandler_CreateMaterialAsset.h"
#include "Handlers/UMCPHandler_CreateMaterialFunctionAsset.h"
#include "Handlers/UMCPHandler_CreateMaterialInstanceAsset.h"
#include "Handlers/UMCPHandler_CreateStructAsset.h"
#include "Handlers/UMCPHandler_DeleteAsset.h"
#include "Handlers/UMCPHandler_DeleteBlueprintGraph.h"
#include "Handlers/UMCPHandler_DeleteNodeFromGraph.h"
#include "Handlers/UMCPHandler_DiffTwoBlueprints.h"
#include "Handlers/UMCPHandler_DisconnectPins.h"
#include "Handlers/UMCPHandler_DumpBlueprint.h"
#include "Handlers/UMCPHandler_DumpProperties.h"
#include "Handlers/UMCPHandler_DumpGraphs.h"
#include "Handlers/UMCPHandler_DumpMaterialInstanceParameters.h"
#include "Handlers/UMCPHandler_DuplicateNodesInGraph.h"
#include "Handlers/UMCPHandler_FindAssetReferences.h"
#include "Handlers/UMCPHandler_FindMaterialReferences.h"
#include "Handlers/UMCPHandler_GetNodeComment.h"
#include "Handlers/UMCPHandler_GetPinDetails.h"
#include "Handlers/UMCPHandler_ListAnimSlotNames.h"
#include "Handlers/UMCPHandler_ListAnimSyncGroups.h"
#include "Handlers/UMCPHandler_ListBlueprintAssets.h"
#include "Handlers/UMCPHandler_ListOpenAssetEditors.h"
#include "Handlers/UMCPHandler_ListBlueprintComponents.h"
#include "Handlers/UMCPHandler_ListBlueprintInterfaces.h"
#include "Handlers/UMCPHandler_ListClassProperties.h"
#include "Handlers/UMCPHandler_ListEventDispatchers.h"
#include "Handlers/UMCPHandler_OpenAssetEditor.h"
#include "Handlers/UMCPHandler_RefreshAllNodesInGraph.h"
#include "Handlers/UMCPHandler_RemoveAnimStateFromMachine.h"
#include "Handlers/UMCPHandler_RemoveBlueprintComponent.h"
#include "Handlers/UMCPHandler_RemoveBlueprintInterface.h"
#include "Handlers/UMCPHandler_RemoveBlueprintVariable.h"
#include "Handlers/UMCPHandler_RemoveFunctionParameter.h"
#include "Handlers/UMCPHandler_RemoveStructField.h"
#include "Handlers/UMCPHandler_RenameAsset.h"
#include "Handlers/UMCPHandler_RenameBlueprintGraph.h"
#include "Handlers/UMCPHandler_ReparentBlueprint.h"
#include "Handlers/UMCPHandler_ReparentMaterialInstance.h"
#include "Handlers/UMCPHandler_ReplaceFunctionCallsInBlueprint.h"
#include "Handlers/UMCPHandler_RestoreAsset.h"
#include "Handlers/UMCPHandler_SearchAssets.h"
#include "Handlers/UMCPHandler_SearchSpawnableNodeTypes.h"
#include "Handlers/UMCPHandler_SearchTypeUsageInBlueprints.h"
#include "Handlers/UMCPHandler_SearchUnrealClasses.h"
#include "Handlers/UMCPHandler_SearchWithinBlueprints.h"
#include "Handlers/UMCPHandler_SetAnimStateAnimation.h"
#include "Handlers/UMCPHandler_SetAnimStateBlendSpace.h"
#include "Handlers/UMCPHandler_SetAnimTransitionRule.h"
#include "Handlers/UMCPHandler_SetBlendSpaceSamplePoints.h"
#include "Handlers/UMCPHandler_SetBlueprintVariableMetadata.h"
#include "Handlers/UMCPHandler_SetClassDefaultValue.h"
#include "Handlers/UMCPHandler_SetMaterialInstanceParameter.h"
#include "Handlers/UMCPHandler_SetMaterialProperty.h"
#include "Handlers/UMCPHandler_SetNodeComment.h"
#include "Handlers/UMCPHandler_SetProperties.h"
#include "Handlers/UMCPHandler_SetNodePositions.h"
#include "Handlers/UMCPHandler_SetPinDefaultValues.h"
#include "Handlers/UMCPHandler_ShowCommands.h"
#include "Handlers/UMCPHandler_SpawnNodes.h"

View File

@@ -1659,11 +1659,30 @@ TArray<UClass*> MCPUtils::CollectHandlerClasses()
FString MCPUtils::GetToolName(UClass* HandlerClass)
{
FString Name = HandlerClass->GetName();
// Strip "MCP_" prefix
if (Name.StartsWith(TEXT("MCP_")))
Name = Name.Mid(4);
// Strip the remaining underscore between group and action (e.g. "Blueprint_Create" -> "BlueprintCreate")
int32 UnderscoreIdx;
if (Name.FindChar(TEXT('_'), UnderscoreIdx))
{
return Name.Mid(UnderscoreIdx + 1);
}
Name = Name.Left(UnderscoreIdx) + Name.Mid(UnderscoreIdx + 1);
return Name;
}
// ============================================================
// GetToolGroup — derive group name from handler class name
// ============================================================
FString MCPUtils::GetToolGroup(UClass* HandlerClass)
{
FString Name = HandlerClass->GetName();
// Strip "MCP_" prefix
if (Name.StartsWith(TEXT("MCP_")))
Name = Name.Mid(4);
// Everything before the underscore is the group
int32 UnderscoreIdx;
if (Name.FindChar(TEXT('_'), UnderscoreIdx))
return Name.Left(UnderscoreIdx);
return Name;
}

View File

@@ -300,6 +300,7 @@ public:
// ----- Command help -----
// Derive tool name from handler class name: "MCPHandler_FooBar" → "FooBar"
static FString GetToolName(UClass* HandlerClass);
static FString GetToolGroup(UClass* HandlerClass);
static FString FormatPropertyType(FProperty* Prop);
static void FormatCommandHelp(UClass* HandlerClass, FStringBuilderBase& Result);