#pragma once #include "CoreMinimal.h" #include "MCPHandler.h" #include "MCPFetcher.h" #include "MCPUtils.h" #include "Engine/Blueprint.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Blueprint_SetVariableMetadata.generated.h" // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- UCLASS() class UMCP_Blueprint_SetVariableMetadata : public UObject, public IMCPHandler { GENERATED_BODY() public: UPROPERTY(meta=(Description="Blueprint name or package path")) FString Blueprint; UPROPERTY(meta=(Description="Name of the variable to modify")) FString Variable; UPROPERTY(meta=(Optional, Description="Category to assign the variable to")) FString Category; UPROPERTY(meta=(Optional, Description="Tooltip text for the variable")) FString Tooltip; UPROPERTY(meta=(Optional, Description="Replication mode: none, replicated, or repNotify")) FString Replication; UPROPERTY(meta=(Optional, Description="If true, expose this variable on spawn")) bool ExposeOnSpawn = false; UPROPERTY(meta=(Optional, Description="If true, mark the variable as private")) bool IsPrivate = false; UPROPERTY(meta=(Optional, Description="Editability mode: editAnywhere, editDefaultsOnly, editInstanceOnly, or none")) FString Editability; virtual FString GetDescription() const override { return TEXT("Set variable metadata properties such as category, tooltip, " "replication, editability, and visibility flags."); } virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override { MCPFetcher F(Result); UBlueprint* BP = F.Walk(Blueprint).Cast(); if (!BP) return; // Find the variable using Identifies for consistent name matching FBPVariableDescription* VarDesc = nullptr; for (FBPVariableDescription& Var : BP->NewVariables) { if (MCPUtils::FormatName(Var) == Variable || Var.VarName.ToString().Equals(Variable, ESearchCase::IgnoreCase)) { VarDesc = &Var; break; } } if (!VarDesc) { Result.Appendf(TEXT("ERROR: Variable '%s' not found in %s.\nAvailable variables:\n"), *Variable, *MCPUtils::FormatName(BP)); for (const FBPVariableDescription& Var : BP->NewVariables) { Result.Appendf(TEXT(" %s\n"), *MCPUtils::FormatName(Var)); } return; } FName VarFName = VarDesc->VarName; int32 ChangeCount = 0; F.PreEdit(); // Category if (Json->HasField(TEXT("category"))) { VarDesc->Category = FText::FromString(Category); FBlueprintEditorUtils::SetBlueprintVariableCategory(BP, VarFName, nullptr, FText::FromString(Category)); Result.Appendf(TEXT("Set category to '%s'.\n"), *Category); ChangeCount++; } // Tooltip if (Json->HasField(TEXT("tooltip"))) { FBlueprintEditorUtils::SetBlueprintVariableMetaData(BP, VarFName, nullptr, TEXT("tooltip"), Tooltip); Result.Appendf(TEXT("Set tooltip to '%s'.\n"), *Tooltip); ChangeCount++; } // Replication if (Json->HasField(TEXT("replication"))) { if (Replication == TEXT("none")) { VarDesc->PropertyFlags &= ~CPF_Net; VarDesc->PropertyFlags &= ~CPF_RepNotify; VarDesc->RepNotifyFunc = NAME_None; } else if (Replication == TEXT("replicated")) { VarDesc->PropertyFlags |= CPF_Net; VarDesc->PropertyFlags &= ~CPF_RepNotify; VarDesc->RepNotifyFunc = NAME_None; } else if (Replication == TEXT("repNotify")) { VarDesc->PropertyFlags |= CPF_Net | CPF_RepNotify; VarDesc->RepNotifyFunc = FName(*FString::Printf(TEXT("OnRep_%s"), *Variable)); } else { Result.Appendf(TEXT("ERROR: Invalid replication value '%s'. Valid: none, replicated, repNotify\n"), *Replication); return; } Result.Appendf(TEXT("Set replication to '%s'.\n"), *Replication); ChangeCount++; } // ExposeOnSpawn if (Json->HasField(TEXT("exposeOnSpawn"))) { if (ExposeOnSpawn) VarDesc->PropertyFlags |= CPF_ExposeOnSpawn; else VarDesc->PropertyFlags &= ~CPF_ExposeOnSpawn; Result.Appendf(TEXT("Set exposeOnSpawn to %s.\n"), ExposeOnSpawn ? TEXT("true") : TEXT("false")); ChangeCount++; } // isPrivate if (Json->HasField(TEXT("isPrivate"))) { FBlueprintEditorUtils::SetBlueprintVariableMetaData(BP, VarFName, nullptr, TEXT("BlueprintPrivate"), IsPrivate ? TEXT("true") : TEXT("false")); Result.Appendf(TEXT("Set isPrivate to %s.\n"), IsPrivate ? TEXT("true") : TEXT("false")); ChangeCount++; } // Editability if (Json->HasField(TEXT("editability"))) { VarDesc->PropertyFlags &= ~(CPF_Edit | CPF_DisableEditOnInstance | CPF_DisableEditOnTemplate); if (Editability == TEXT("editAnywhere")) { VarDesc->PropertyFlags |= CPF_Edit; } else if (Editability == TEXT("editDefaultsOnly")) { VarDesc->PropertyFlags |= CPF_Edit | CPF_DisableEditOnInstance; } else if (Editability == TEXT("editInstanceOnly")) { VarDesc->PropertyFlags |= CPF_Edit | CPF_DisableEditOnTemplate; } else if (Editability != TEXT("none")) { Result.Appendf(TEXT("ERROR: Invalid editability value '%s'. Valid: editAnywhere, editDefaultsOnly, editInstanceOnly, none\n"), *Editability); return; } Result.Appendf(TEXT("Set editability to '%s'.\n"), *Editability); ChangeCount++; } if (ChangeCount == 0) { Result.Append(TEXT("ERROR: No metadata fields specified. Provide at least one of: category, tooltip, replication, exposeOnSpawn, isPrivate, editability\n")); return; } F.PostEdit(); bool bSaved = MCPUtils::SaveBlueprintPackage(BP); Result.Appendf(TEXT("Updated %d field(s) on %s in %s.%s\n"), ChangeCount, *VarFName.ToString(), *MCPUtils::FormatName(BP), bSaved ? TEXT("") : TEXT(" WARNING: save failed.")); } };