diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_GetDetails.h b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_GetDetails.h deleted file mode 100644 index 6ef55562..00000000 --- a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_GetDetails.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "MCPHandler.h" -#include "MCPFetcher.h" -#include "MCPUtils.h" -#include "EdGraph/EdGraphPin.h" -#include "GraphPin_GetDetails.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -// ============================================================ -// HandleGetPinInfo — detailed information about a specific pin -// ============================================================ - -UCLASS() -class UMCP_GraphPin_GetDetails : public UObject, public IMCPHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Path to the pin, e.g. /Game/Widgets/WB_Hotkeys,node:MyNode,pin:Result")) - FString Pin; - - virtual FString GetDescription() const override - { - return TEXT("Get detailed information about a specific pin on a blueprint node, " - "including type, connections, and default values."); - } - - virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override - { - MCPFetcher F(Result); - UEdGraphPin* P = F.Walk(Pin).Cast(); - if (!P) return; - - Result.Appendf(TEXT("Direction: %s\n"), P->Direction == EGPD_Input ? TEXT("Input") : TEXT("Output")); - Result.Appendf(TEXT("Type: %s\n"), *MCPUtils::FormatPinType(P)); - - if (P->PinType.IsArray()) Result.Append(TEXT("Container: Array\n")); - else if (P->PinType.IsSet()) Result.Append(TEXT("Container: Set\n")); - else if (P->PinType.IsMap()) Result.Append(TEXT("Container: Map\n")); - - if (P->PinType.bIsReference) Result.Append(TEXT("IsReference: true\n")); - if (P->PinType.bIsConst) Result.Append(TEXT("IsConst: true\n")); - - if (!P->DefaultValue.IsEmpty()) - Result.Appendf(TEXT("DefaultValue: %s\n"), *P->DefaultValue); - if (!P->DefaultTextValue.IsEmpty()) - Result.Appendf(TEXT("DefaultTextValue: %s\n"), *P->DefaultTextValue.ToString()); - if (P->DefaultObject) - Result.Appendf(TEXT("DefaultObject: %s\n"), *P->DefaultObject->GetPathName()); - - // Connected pins - for (UEdGraphPin* Linked : P->LinkedTo) - { - if (!Linked || !Linked->GetOwningNode()) continue; - Result.Appendf(TEXT("Connection: %s :: %s\n"), - *MCPUtils::FormatName(Linked->GetOwningNode()), - *MCPUtils::FormatName(Linked)); - } - } -}; diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_SetDefault.h b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_SetDefault.h index 5ac2c925..7c17ddb5 100644 --- a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_SetDefault.h +++ b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/GraphPin_SetDefault.h @@ -5,6 +5,7 @@ #include "MCPFetcher.h" #include "MCPUtils.h" #include "EdGraph/EdGraphPin.h" +#include "EdGraphSchema_K2.h" #include "GraphPin_SetDefault.generated.h" @@ -17,6 +18,9 @@ struct FSetPinDefaultEntry { GENERATED_BODY() + UPROPERTY() + FString Node; + UPROPERTY() FString Pin; @@ -31,7 +35,10 @@ class UMCP_GraphPin_SetDefault : public UObject, public IMCPHandler GENERATED_BODY() public: - UPROPERTY(meta=(Description="Array of {pin, value} objects. Pin is a path like /Game/Foo,graph:EventGraph,node:MyNode,pin:InputPin")) + UPROPERTY(meta=(Description="Graph path, e.g. /Game/Foo,graph:EventGraph")) + FString Graph; + + UPROPERTY(meta=(Description="Array of {node, pin, value} objects")) FMCPJsonArray Pins; virtual FString GetDescription() const override @@ -41,18 +48,24 @@ public: virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override { + // Fetch the graph once. + MCPFetcher GraphFetcher(Result); + UEdGraph* GraphObj = GraphFetcher.Walk(Graph).Cast(); + if (!GraphObj) return; + int32 SuccessCount = 0; int32 TotalCount = Pins.Array.Num(); TSet ModifiedNodes; + GraphFetcher.PreEdit(); for (const TSharedPtr& PinVal : Pins.Array) { FSetPinDefaultEntry Entry; if (!MCPUtils::PopulateFromJson(FSetPinDefaultEntry::StaticStruct(), &Entry, PinVal, Result)) continue; - MCPFetcher F(Result); - UEdGraphPin* Pin = F.Walk(Entry.Pin).Cast(); + MCPFetcher F(Result, GraphObj); + UEdGraphPin* Pin = F.Node(Entry.Node).Pin(Entry.Pin).Cast(); if (!Pin) continue; UEdGraphNode* Node = Pin->GetOwningNode(); @@ -63,21 +76,33 @@ public: continue; } - const UEdGraphSchema* Schema = Node->GetGraph()->GetSchema(); - if (Schema) - Schema->TrySetDefaultValue(*Pin, Entry.Value); - else - Pin->DefaultValue = Entry.Value; + const UEdGraphSchema_K2* Schema = Cast(Node->GetGraph()->GetSchema()); + check(Schema); + + // Parse and validate the value before applying. + FString UseDefaultValue; + TObjectPtr UseDefaultObject = nullptr; + FText UseDefaultText; + Schema->GetPinDefaultValuesFromString(Pin->PinType, Node, Entry.Value, UseDefaultValue, UseDefaultObject, UseDefaultText, false); + FString Error = Schema->IsPinDefaultValid(Pin, UseDefaultValue, UseDefaultObject, UseDefaultText); + if (!Error.IsEmpty()) + { + Result.Appendf(TEXT("error: %s: %s\n"), *MCPUtils::FormatName(Pin), *Error); + continue; + } + + Pin->Modify(); + Schema->TrySetDefaultValue(*Pin, Entry.Value); SuccessCount++; ModifiedNodes.Add(Node); - F.PostEdit(); } for (UEdGraphNode* Node : ModifiedNodes) { Node->ReconstructNode(); } + GraphFetcher.PostEdit(); Result.Appendf(TEXT("Set %d/%d pin defaults.\n"), SuccessCount, TotalCount); } diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Material_DumpProperties.h b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Material_DumpProperties.h deleted file mode 100644 index d46bddfc..00000000 --- a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Material_DumpProperties.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "MCPHandler.h" -#include "MCPFetcher.h" -#include "MCPUtils.h" -#include "Materials/Material.h" -#include "MaterialDomain.h" -#include "Material_DumpProperties.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UMCP_Material_DumpProperties : public UObject, public IMCPHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Material path")) - FString Path; - - virtual FString GetDescription() const override - { - return TEXT("List top-level material properties such as domain, blend mode, shading model, and usage flags."); - } - - virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override - { - MCPFetcher F(Result); - UMaterial* Mat = F.Asset(Path).Cast(); - if (!Mat) return; - - 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(" shadingModel = %s\n"), *MCPUtils::EnumToString(Mat->GetShadingModels().GetFirstShadingModel(), TEXT("MSM_"))); - Result.Appendf(TEXT(" opacityMaskClipValue = %g\n"), Mat->OpacityMaskClipValue); - Result.Appendf(TEXT(" twoSided = %s\n"), Mat->TwoSided ? TEXT("true") : TEXT("false")); - Result.Appendf(TEXT(" bUsedWithSkeletalMesh = %s\n"), Mat->bUsedWithSkeletalMesh ? TEXT("true") : TEXT("false")); - Result.Appendf(TEXT(" bUsedWithMorphTargets = %s\n"), Mat->bUsedWithMorphTargets ? TEXT("true") : TEXT("false")); - Result.Appendf(TEXT(" bUsedWithNiagaraSprites = %s\n"), Mat->bUsedWithNiagaraSprites ? TEXT("true") : TEXT("false")); - Result.Appendf(TEXT(" ditheredLODTransition = %s\n"), Mat->DitheredLODTransition ? TEXT("true") : TEXT("false")); - Result.Appendf(TEXT(" bAllowNegativeEmissiveColor = %s\n"), Mat->bAllowNegativeEmissiveColor ? TEXT("true") : TEXT("false")); - } -}; diff --git a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Material_SetProperty.h b/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Material_SetProperty.h deleted file mode 100644 index 3288ad4b..00000000 --- a/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Material_SetProperty.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "MCPHandler.h" -#include "MCPFetcher.h" -#include "MCPUtils.h" -#include "Materials/Material.h" -#include "MaterialDomain.h" -#include "Material_SetProperty.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UMCP_Material_SetProperty : public UObject, public IMCPHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Material path")) - FString Path; - - UPROPERTY(meta=(Description="Property name to set (domain, blendMode, twoSided, shadingModel, opacity, opacityMaskClipValue, bUsedWithSkeletalMesh, bUsedWithMorphTargets, bUsedWithNiagaraSprites, ditheredLODTransition, bAllowNegativeEmissiveColor)")) - FString Property; - - UPROPERTY(meta=(Description="Value to set")) - FString Value; - - virtual FString GetDescription() const override - { - return TEXT("Set a top-level material property such as domain, blend mode, shading model, or usage flags."); - } - - virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override - { - MCPFetcher F(Result); - UMaterial* Mat = F.Asset(Path).Cast(); - if (!Mat) return; - - // Parse value and build setter. Validation happens here so we can bail before PreEdit. - TFunction Setter; - - if (Property == TEXT("domain")) - { - EMaterialDomain NewDomain; - if (!MCPUtils::StringToEnum(Value, NewDomain, Result, TEXT("MD_"))) return; - Setter = [Mat, NewDomain]() { Mat->MaterialDomain = NewDomain; }; - } - else if (Property == TEXT("blendMode")) - { - EBlendMode NewBlend; - if (!MCPUtils::StringToEnum(Value, NewBlend, Result, TEXT("BLEND_"))) return; - Setter = [Mat, NewBlend]() { Mat->BlendMode = NewBlend; }; - } - else if (Property == TEXT("shadingModel")) - { - EMaterialShadingModel NewModel; - if (!MCPUtils::StringToEnum(Value, NewModel, Result, TEXT("MSM_"))) return; - Setter = [Mat, NewModel]() { Mat->SetShadingModel(NewModel); }; - } - else if (Property == TEXT("opacity") || Property == TEXT("opacityMaskClipValue")) - { - float FloatVal = FCString::Atof(*Value); - Setter = [Mat, FloatVal]() { Mat->OpacityMaskClipValue = FloatVal; }; - } - else if (Property == TEXT("twoSided")) - { - bool bVal; if (!MCPUtils::StringToBool(Value, bVal, Result)) return; - Setter = [Mat, bVal]() { Mat->TwoSided = bVal ? 1 : 0; }; - } - else if (Property == TEXT("bUsedWithSkeletalMesh")) - { - bool bVal; if (!MCPUtils::StringToBool(Value, bVal, Result)) return; - Setter = [Mat, bVal]() { Mat->bUsedWithSkeletalMesh = bVal ? 1 : 0; }; - } - else if (Property == TEXT("bUsedWithMorphTargets")) - { - bool bVal; if (!MCPUtils::StringToBool(Value, bVal, Result)) return; - Setter = [Mat, bVal]() { Mat->bUsedWithMorphTargets = bVal ? 1 : 0; }; - } - else if (Property == TEXT("bUsedWithNiagaraSprites")) - { - bool bVal; if (!MCPUtils::StringToBool(Value, bVal, Result)) return; - Setter = [Mat, bVal]() { Mat->bUsedWithNiagaraSprites = bVal ? 1 : 0; }; - } - else if (Property == TEXT("ditheredLODTransition") || Property == TEXT("DitheredLODTransition")) - { - bool bVal; if (!MCPUtils::StringToBool(Value, bVal, Result)) return; - Setter = [Mat, bVal]() { Mat->DitheredLODTransition = bVal ? 1 : 0; }; - } - else if (Property == TEXT("bAllowNegativeEmissiveColor")) - { - bool bVal; if (!MCPUtils::StringToBool(Value, bVal, Result)) return; - Setter = [Mat, bVal]() { Mat->bAllowNegativeEmissiveColor = bVal ? 1 : 0; }; - } - else - { - Result.Appendf(TEXT("ERROR: Unknown property '%s'. Valid: domain, blendMode, twoSided, shadingModel, " - "opacity, opacityMaskClipValue, bUsedWithSkeletalMesh, bUsedWithMorphTargets, " - "bUsedWithNiagaraSprites, ditheredLODTransition, bAllowNegativeEmissiveColor\n"), *Property); - return; - } - - // Apply the change between PreEdit/PostEdit. - F.PreEdit(); - Setter(); - F.PostEdit(); - MCPUtils::SaveMaterialPackage(Mat); - - Result.Appendf(TEXT("Set %s on %s\n"), *Property, *MCPUtils::FormatName(Mat)); - } -};