Files
integration/Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers/Property_Dump.h
2026-03-13 05:34:19 -04:00

98 lines
3.0 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPProperty.h"
#include "MCPUtils.h"
#include "Property_Dump.generated.h"
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
UCLASS()
class UMCP_Property_Dump : public UObject, public IMCPHandler
{
GENERATED_BODY()
public:
UPROPERTY(meta=(Description="MCPFetcher path to the object (e.g. /Game/Materials/M_Gold or /Game/Tangibles/TAN_Char,component:Mesh0)"))
FString Path;
UPROPERTY(meta=(Optional, Description="Substring filter for property names"))
FString Query;
UPROPERTY(meta=(Optional, Description="Truncate values to 80 characters (default true)"))
bool Truncate = true;
UPROPERTY(meta=(Optional, Description="Only show properties declared on the object's own class, not inherited ones"))
bool Local = false;
virtual FString GetDescription() const override
{
return TEXT("List all blueprint-visible properties on an object resolved via MCPFetcher path, "
"showing current values and which properties are editable.");
}
virtual void Handle(FStringBuilderBase& Result) override
{
// Resolve the path to an object and get its editable template.
MCPFetcher F(Result);
UObject* Template = F.Walk(Path).Template().Cast<UObject>();
if (!Template) return;
TArray<MCPProperty> Props = MCPProperty::GetAllSubstring(Template, CPF_Edit, Query);
if (Local)
{
UClass* ObjClass = Template->GetClass();
Props.RemoveAll([ObjClass](const MCPProperty& P) { return P->GetOwnerStruct() != ObjClass; });
}
// Group properties by category.
TMap<FString, TArray<MCPProperty>> ByCategory;
for (MCPProperty& P : Props)
{
FString Category = P->HasMetaData(TEXT("Category")) ? P->GetMetaData(TEXT("Category")) : FString();
ByCategory.FindOrAdd(Category).Add(P);
}
// Sort category names, putting empty category last.
TArray<FString> Categories;
ByCategory.GetKeys(Categories);
Categories.Sort([](const FString& A, const FString& B) {
if (A.IsEmpty()) return false;
if (B.IsEmpty()) return true;
return A < B;
});
for (const FString& Category : Categories)
{
if (Category.IsEmpty())
Result.Append(TEXT("\nUncategorized:\n"));
else
Result.Appendf(TEXT("\n%s:\n"), *Category);
for (MCPProperty& P : ByCategory[Category])
{
FString PropName = MCPUtils::FormatName(P.Prop);
FString ValueStr = P.GetText();
if (Truncate && (ValueStr.Len() > 80))
ValueStr = ValueStr.Left(80) + TEXT("...");
bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst);
Result.Appendf(TEXT(" %s %s %s = %s\n"),
bEditable ? TEXT("editable") : TEXT("readonly"),
*MCPUtils::FormatPropertyType(P.Prop),
*PropName,
*ValueStr);
}
}
if (Props.IsEmpty())
Result.Append(TEXT(" (no blueprint-visible properties found)\n"));
}
};