#pragma once #include "CoreMinimal.h" #include "MCPHandler.h" #include "MCPAssets.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 Assets; if (!Assets.Exact(MaterialFunction).Errors(Result).ENone().ETwo().Load()) return; MatFunc = Assets.Object(); } else { MCPAssets 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(); 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")); } };