98 lines
3.0 KiB
C++
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"));
|
|
}
|
|
};
|