More refactoring.
This commit is contained in:
@@ -41,7 +41,7 @@ public:
|
|||||||
{
|
{
|
||||||
// Resolve the path to an object and get its editable template.
|
// Resolve the path to an object and get its editable template.
|
||||||
MCPFetcher F;
|
MCPFetcher F;
|
||||||
UObject* Template = F.Walk(Path).Template().Cast<UObject>();
|
UObject* Template = F.Walk(Path).Cast<UObject>();
|
||||||
if (!Template) return;
|
if (!Template) return;
|
||||||
|
|
||||||
TArray<MCPProperty> Props = MCPProperty::GetAllSubstring(Template, CPF_Edit, Query);
|
TArray<MCPProperty> Props = MCPProperty::GetAllSubstring(Template, CPF_Edit, Query);
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ public:
|
|||||||
virtual void Handle() override
|
virtual void Handle() override
|
||||||
{
|
{
|
||||||
MCPFetcher F;
|
MCPFetcher F;
|
||||||
UObject* Template = F.Walk(Path).Template().Cast<UObject>();
|
UObject* Obj = F.Walk(Path).Cast<UObject>();
|
||||||
if (!Template) return;
|
if (!Obj) return;
|
||||||
|
|
||||||
MCPProperty P = MCPProperty::GetOneExactMatch(Template, CPF_Edit, Property);
|
MCPProperty P = MCPProperty::GetOneExactMatch(Obj, CPF_Edit, Property);
|
||||||
if (!P) return;
|
if (!P) return;
|
||||||
|
|
||||||
UMCPServer::Print(P.GetText());
|
UMCPServer::Print(P.GetText());
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public:
|
|||||||
{
|
{
|
||||||
// Resolve the path to an object and get its editable template.
|
// Resolve the path to an object and get its editable template.
|
||||||
MCPFetcher F;
|
MCPFetcher F;
|
||||||
UObject* Template = F.Walk(Path).Template().Cast<UObject>();
|
UObject* Obj = F.Walk(Path).Cast<UObject>();
|
||||||
if (!Template) return;
|
if (!Obj) return;
|
||||||
|
|
||||||
if (!Properties.Json || Properties.Json->Values.Num() == 0)
|
if (!Properties.Json || Properties.Json->Values.Num() == 0)
|
||||||
{
|
{
|
||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
TArray<TPair<MCPProperty, FString>> Resolved;
|
TArray<TPair<MCPProperty, FString>> Resolved;
|
||||||
for (const auto& Pair : Properties.Json->Values)
|
for (const auto& Pair : Properties.Json->Values)
|
||||||
{
|
{
|
||||||
MCPProperty P = MCPProperty::GetOneExactMatch(Template, CPF_Edit, Pair.Key);
|
MCPProperty P = MCPProperty::GetOneExactMatch(Obj, CPF_Edit, Pair.Key);
|
||||||
if (!P) return;
|
if (!P) return;
|
||||||
|
|
||||||
FString ValueStr;
|
FString ValueStr;
|
||||||
@@ -70,7 +70,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save.
|
// Save.
|
||||||
bool bSaved = MCPUtils::SaveGenericPackage(Template);
|
bool bSaved = MCPUtils::SaveGenericPackage(Obj);
|
||||||
|
|
||||||
UMCPServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
|
UMCPServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
|
||||||
if (!bSaved)
|
if (!bSaved)
|
||||||
|
|||||||
@@ -68,19 +68,8 @@ public:
|
|||||||
virtual void Handle() override
|
virtual void Handle() override
|
||||||
{
|
{
|
||||||
UMCPServer::Printf(TEXT("\n"));
|
UMCPServer::Printf(TEXT("\n"));
|
||||||
|
|
||||||
EmitCommandList();
|
EmitCommandList();
|
||||||
|
UMCPServer::Printf(TEXT("\n"));
|
||||||
// Append Path documentation.
|
MCPFetcher::PrintDocs();
|
||||||
UMCPServer::Print(TEXT("\n"));
|
|
||||||
UMCPServer::Print(TEXT("Some commands take a Path parameter. A Path starts with an asset\n"));
|
|
||||||
UMCPServer::Print(TEXT("package path (e.g. /Game/Widgets/WB_Hotkeys), followed by zero or\n"));
|
|
||||||
UMCPServer::Print(TEXT("more comma-separated steps that navigate into the asset:\n"));
|
|
||||||
UMCPServer::Print(TEXT("\n"));
|
|
||||||
for (const MCPFetcher::FWalker& W : MCPFetcher::GetWalkerTable())
|
|
||||||
{
|
|
||||||
UMCPServer::Printf(TEXT(" %s — %s\n"), W.Key, W.Description);
|
|
||||||
}
|
|
||||||
UMCPServer::Print(TEXT("\nExample: /Game/Widgets/WB_Hotkeys,graph:EventGraph,node:Self_Reference_03,pin:Result\n"));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,30 @@
|
|||||||
#include "Engine/LevelScriptBlueprint.h"
|
#include "Engine/LevelScriptBlueprint.h"
|
||||||
#include "Subsystems/AssetEditorSubsystem.h"
|
#include "Subsystems/AssetEditorSubsystem.h"
|
||||||
|
|
||||||
|
MCPFetcher::WalkFunc MCPFetcher::GetWalker(const FString& Step)
|
||||||
|
{
|
||||||
|
if (Step.Equals(TEXT("graph"), ESearchCase::IgnoreCase)) return &MCPFetcher::Graph;
|
||||||
|
if (Step.Equals(TEXT("node"), ESearchCase::IgnoreCase)) return &MCPFetcher::Node;
|
||||||
|
if (Step.Equals(TEXT("pin"), ESearchCase::IgnoreCase)) return &MCPFetcher::Pin;
|
||||||
|
if (Step.Equals(TEXT("component"), ESearchCase::IgnoreCase)) return &MCPFetcher::Component;
|
||||||
|
if (Step.Equals(TEXT("levelblueprint"), ESearchCase::IgnoreCase)) return &MCPFetcher::LevelBlueprint;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MCPFetcher::PrintDocs()
|
||||||
|
{
|
||||||
|
UMCPServer::Print(TEXT("Some commands take a Path parameter. A Path starts with an asset\n"));
|
||||||
|
UMCPServer::Print(TEXT("package path (e.g. /Game/Widgets/WB_Hotkeys), followed by zero or\n"));
|
||||||
|
UMCPServer::Print(TEXT("more comma-separated steps that navigate into the asset:\n\n"));
|
||||||
|
UMCPServer::Print(TEXT(" graph — Find a named UEdGraph (blank name for material graphs)\n"));
|
||||||
|
UMCPServer::Print(TEXT(" node — Find a named UEdGraphNode within a graph or blueprint\n"));
|
||||||
|
UMCPServer::Print(TEXT(" pin — Find a named UEdGraphPin on a node\n"));
|
||||||
|
UMCPServer::Print(TEXT(" component — Find a named component in a Blueprint's SCS\n"));
|
||||||
|
UMCPServer::Print(TEXT(" levelblueprint — Get the level blueprint from a UWorld\n"));
|
||||||
|
UMCPServer::Print(TEXT("\nExample: /Game/Widgets/WB_Hotkeys,graph:EventGraph,node:Self_Reference_03,pin:Result\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MCPFetcher::SetObj(UObject* InObj) { UMCPServer::AddTouchedObject(InObj); Obj = InObj; ResultPin = nullptr; }
|
void MCPFetcher::SetObj(UObject* InObj) { UMCPServer::AddTouchedObject(InObj); Obj = InObj; ResultPin = nullptr; }
|
||||||
void MCPFetcher::SetPin(UEdGraphPin* InPin) { ResultPin = InPin; Obj = nullptr; }
|
void MCPFetcher::SetPin(UEdGraphPin* InPin) { ResultPin = InPin; Obj = nullptr; }
|
||||||
|
|
||||||
@@ -36,17 +60,7 @@ MCPFetcher& MCPFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expected)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TArray<MCPFetcher::FWalker>& MCPFetcher::GetWalkerTable()
|
|
||||||
{
|
|
||||||
static TArray<FWalker> Table = {
|
|
||||||
{ TEXT("graph"), TEXT("Find a named UEdGraph (blank name for material graphs)"), &MCPFetcher::Graph },
|
|
||||||
{ TEXT("node"), TEXT("Find a named UEdGraphNode within a graph or blueprint"), &MCPFetcher::Node },
|
|
||||||
{ TEXT("pin"), TEXT("Find a named UEdGraphPin on a node"), &MCPFetcher::Pin },
|
|
||||||
{ TEXT("component"), TEXT("Find a named component in a Blueprint's SCS"), &MCPFetcher::Component },
|
|
||||||
{ TEXT("levelblueprint"), TEXT("Get the level blueprint from a UWorld"), &MCPFetcher::LevelBlueprint },
|
|
||||||
};
|
|
||||||
return Table;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCPFetcher& MCPFetcher::Walk(const FString& Path)
|
MCPFetcher& MCPFetcher::Walk(const FString& Path)
|
||||||
{
|
{
|
||||||
@@ -73,13 +87,13 @@ MCPFetcher& MCPFetcher::Walk(const FString& Path)
|
|||||||
if (!Segments[i].Split(TEXT(":"), &Key, &Value))
|
if (!Segments[i].Split(TEXT(":"), &Key, &Value))
|
||||||
Key = Segments[i];
|
Key = Segments[i];
|
||||||
|
|
||||||
const FWalker* W = GetWalker(Key);
|
WalkFunc Func = GetWalker(Key);
|
||||||
if (!W)
|
if (!Func)
|
||||||
{
|
{
|
||||||
UMCPServer::Printf(TEXT("ERROR: Unknown path step '%s'\n"), *Key);
|
UMCPServer::Printf(TEXT("ERROR: Unknown path step '%s'\n"), *Key);
|
||||||
return SetError();
|
return SetError();
|
||||||
}
|
}
|
||||||
(this->*W->Func)(Value);
|
(this->*Func)(Value);
|
||||||
if (bError) return *this;
|
if (bError) return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,16 +149,6 @@ bool MCPFetcher::CheckAssetIsA(UClass* StaticClass)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MCPFetcher::FWalker* MCPFetcher::GetWalker(const FString& Key)
|
|
||||||
{
|
|
||||||
for (const FWalker& W : GetWalkerTable())
|
|
||||||
{
|
|
||||||
if (Key.Equals(W.Key, ESearchCase::IgnoreCase))
|
|
||||||
return &W;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCPFetcher& MCPFetcher::Graph(const FString& Value)
|
MCPFetcher& MCPFetcher::Graph(const FString& Value)
|
||||||
{
|
{
|
||||||
if (bError) return *this;
|
if (bError) return *this;
|
||||||
@@ -330,30 +334,6 @@ MCPFetcher& MCPFetcher::LevelBlueprint(const FString& Value)
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCPFetcher& MCPFetcher::Template()
|
|
||||||
{
|
|
||||||
if (bError) return *this;
|
|
||||||
if (!Obj)
|
|
||||||
{
|
|
||||||
UMCPServer::Print(TEXT("ERROR: Template: object is null\n"));
|
|
||||||
return SetError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UBlueprint* BP = ::Cast<UBlueprint>(Obj))
|
|
||||||
{
|
|
||||||
if (!BP->GeneratedClass)
|
|
||||||
{
|
|
||||||
UMCPServer::Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName());
|
|
||||||
return SetError();
|
|
||||||
}
|
|
||||||
SetObj(BP->GeneratedClass->GetDefaultObject());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything else is its own template — no navigation needed.
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCPFetcher& MCPFetcher::ToBlueprint()
|
MCPFetcher& MCPFetcher::ToBlueprint()
|
||||||
{
|
{
|
||||||
if (bError) return *this;
|
if (bError) return *this;
|
||||||
|
|||||||
@@ -35,24 +35,44 @@ bool MCPProperty::SetText(const FString& Value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TArray<MCPProperty> MCPProperty::GetAll(UObject* Obj, EPropertyFlags Flags)
|
void MCPProperty::Collect(UObject *Obj, TArray<MCPProperty> &Props, EPropertyFlags Flags)
|
||||||
{
|
{
|
||||||
TArray<MCPProperty> Result;
|
|
||||||
if (!Obj) return Result;
|
|
||||||
for (TFieldIterator<FProperty> It(Obj->GetClass()); It; ++It)
|
for (TFieldIterator<FProperty> It(Obj->GetClass()); It; ++It)
|
||||||
{
|
{
|
||||||
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
|
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
|
||||||
Result.Emplace(*It, Obj);
|
Props.Emplace(*It, Obj);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<MCPProperty> MCPProperty::GetAll(UObject* Obj, EPropertyFlags Flags)
|
||||||
|
{
|
||||||
|
if (!Obj) return {};
|
||||||
|
TArray<MCPProperty> Result;
|
||||||
|
|
||||||
|
// Blueprints don't have editable properties. So
|
||||||
|
// instead, we fetch properties from the generated CDO,
|
||||||
|
// which is probably what the user intended.
|
||||||
|
//
|
||||||
|
if (UBlueprint *BP = ::Cast<UBlueprint>(Obj))
|
||||||
|
{
|
||||||
|
if (BP->GeneratedClass == nullptr)
|
||||||
|
{
|
||||||
|
UMCPServer::Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
Obj = BP->GeneratedClass->GetDefaultObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
Collect(Obj, Result, Flags);
|
||||||
|
|
||||||
|
// If it's a Material Graph node, also collect properties from
|
||||||
|
// the associated material expression.
|
||||||
|
//
|
||||||
if (UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(Obj))
|
if (UMaterialGraphNode* MatNode = Cast<UMaterialGraphNode>(Obj))
|
||||||
{
|
{
|
||||||
if (UMaterialExpression* Expr = MatNode->MaterialExpression)
|
if (UMaterialExpression* Expr = MatNode->MaterialExpression)
|
||||||
{
|
{
|
||||||
for (TFieldIterator<FProperty> It(Expr->GetClass()); It; ++It)
|
Collect(Expr, Result, Flags);
|
||||||
{
|
|
||||||
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
|
|
||||||
Result.Emplace(*It, Expr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
|
|||||||
@@ -5,79 +5,74 @@
|
|||||||
|
|
||||||
class UEdGraphPin;
|
class UEdGraphPin;
|
||||||
class IAssetEditorInstance;
|
class IAssetEditorInstance;
|
||||||
|
struct FWalker;
|
||||||
|
|
||||||
// Resolves a path string into a UObject or UEdGraphPin.
|
// MCPFetcher: Load an Asset and find an object within it.
|
||||||
|
// To find an object, you use a path. This is typical:
|
||||||
//
|
//
|
||||||
// A path starts with a package path (e.g. "/Game/Widgets/WB_Hotkeys"),
|
// F.Walk(TEXT("/Game/Mat/M_Test,graph,node:Param_1"))
|
||||||
// followed by zero or more comma-separated walker segments of the form
|
|
||||||
// "key:value". Each segment navigates from the current object to a child.
|
|
||||||
//
|
//
|
||||||
// The list of supported walkers is defined by GetWalkerTable().
|
// A path always starts from an asset name. The path above
|
||||||
|
// starts at a material asset, then it walks to the material
|
||||||
|
// graph, then from there to a specific graph node.
|
||||||
//
|
//
|
||||||
// Example paths:
|
// Instead of specifying the path as a string, you can also
|
||||||
// /Game/Widgets/WB_Hotkeys,graph:ReadLuaConfiguration,node:Self_Reference_03,pin:Result
|
// specify it using a sequence of procedural steps, like
|
||||||
// /Game/Tangibles/TAN_Character,component:CharacterMesh0
|
// this:
|
||||||
//
|
//
|
||||||
// Builder-style usage:
|
// F.Asset(TEXT("/Game/Materials/M_Test"));
|
||||||
// MCPFetcher F;
|
// F.Graph();
|
||||||
// if (!F.Walk(Path).Ok()) return;
|
// F.Node(TEXT("Param_1"));
|
||||||
//
|
//
|
||||||
// MCPFetcher F(ExistingObj);
|
// When you're finally at the object you want, you usually
|
||||||
// if (!F.Graph("EventGraph").Node("MyNode").Ok()) return;
|
// use the Cast method to get a pointer to the object.
|
||||||
//
|
//
|
||||||
|
// If any step fails, the MCPFetcher will print an error
|
||||||
|
// message that can be seen by the MCP's caller. It will
|
||||||
|
// also set an error flag. Once the error flag is set, all
|
||||||
|
// further ops become no-ops. At that point, attempting a
|
||||||
|
// Cast will return nullptr.
|
||||||
|
//
|
||||||
|
|
||||||
class MCPFetcher
|
class MCPFetcher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MCPFetcher() {}
|
// Walk a path from an asset to an object
|
||||||
MCPFetcher(UObject* O) : Obj(O) {}
|
// within that asset. If you call walk a
|
||||||
|
// second time, it will walk additional steps.
|
||||||
|
//
|
||||||
|
MCPFetcher& Walk(const FString& Path);
|
||||||
|
|
||||||
// Starting point is always Asset.
|
// Walk a path using individual path
|
||||||
|
// steps instead of a path. All these steps generate
|
||||||
|
// errors if they cannot find the desired element.
|
||||||
|
//
|
||||||
MCPFetcher& Asset(const FString& PackagePath);
|
MCPFetcher& Asset(const FString& PackagePath);
|
||||||
|
|
||||||
// Walk one step.
|
|
||||||
MCPFetcher& Graph(const FString& Value);
|
MCPFetcher& Graph(const FString& Value);
|
||||||
MCPFetcher& Node(const FString& Value);
|
MCPFetcher& Node(const FString& Value);
|
||||||
MCPFetcher& Pin(const FString& Value);
|
MCPFetcher& Pin(const FString& Value);
|
||||||
MCPFetcher& Component(const FString& Value);
|
MCPFetcher& Component(const FString& Value);
|
||||||
MCPFetcher& LevelBlueprint(const FString& Value);
|
MCPFetcher& LevelBlueprint(const FString& Value);
|
||||||
|
|
||||||
// Parse string and walk multiple steps.
|
// The following walkers cannot be invoked from
|
||||||
MCPFetcher& Walk(const FString& Path);
|
// paths, only procedurally. If the current object
|
||||||
|
// is already the target type, they do nothing.
|
||||||
// C++-only walk step: resolve to the editable template
|
// Otherwise, they attempt to convert (e.g. World
|
||||||
// (e.g. Blueprint → CDO, everything else → as-is).
|
// to its level blueprint, Material to its graph).
|
||||||
MCPFetcher& Template();
|
//
|
||||||
|
|
||||||
// C++-only navigation: drill down to a specific type.
|
|
||||||
MCPFetcher& ToBlueprint();
|
MCPFetcher& ToBlueprint();
|
||||||
MCPFetcher& ToGraph();
|
MCPFetcher& ToGraph();
|
||||||
|
|
||||||
// Walker table entry.
|
// Return true if there haven't been any errors.
|
||||||
struct FWalker
|
// Note that errors always automatically generate
|
||||||
{
|
// output to MCPServer::Printf.
|
||||||
const TCHAR* Key; // e.g. "graph", "node", "matexp"
|
//
|
||||||
const TCHAR* Description; // brief help text
|
|
||||||
MCPFetcher& (MCPFetcher::*Func)(const FString& Value);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns the static table of all supported walkers.
|
|
||||||
static const TArray<FWalker>& GetWalkerTable();
|
|
||||||
|
|
||||||
bool Ok() const { return !bError; }
|
bool Ok() const { return !bError; }
|
||||||
UObject* GetObj() const { return Obj; }
|
|
||||||
UObject* GetAsset() const { return OriginalAsset; }
|
|
||||||
template<class T> T* CastAsset()
|
|
||||||
{
|
|
||||||
if (!CheckAssetIsA(T::StaticClass())) return nullptr;
|
|
||||||
return ::Cast<T>(OriginalAsset);
|
|
||||||
}
|
|
||||||
template<class AssetType, class EditorType>
|
|
||||||
EditorType* CastEditor()
|
|
||||||
{
|
|
||||||
if (!CheckAssetIsA(AssetType::StaticClass())) return nullptr;
|
|
||||||
return static_cast<EditorType*>(Editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Try to fetch the current object as a UObject of
|
||||||
|
// the specified type. If it isn't one, generates an
|
||||||
|
// error and returns nullptr.
|
||||||
|
//
|
||||||
template<class T> T *Cast()
|
template<class T> T *Cast()
|
||||||
{
|
{
|
||||||
if (bError) return nullptr;
|
if (bError) return nullptr;
|
||||||
@@ -87,12 +82,55 @@ public:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the current object as a UObject if it is one,
|
||||||
|
// otherwise nullptr. Does not generate errors.
|
||||||
|
//
|
||||||
|
UObject* GetObj() const { return Obj; }
|
||||||
|
|
||||||
|
// Get the asset from where it all began: the first
|
||||||
|
// step in the walk path. If the asset couldn't be
|
||||||
|
// loaded, returns nullptr. Does not generate errors.
|
||||||
|
//
|
||||||
|
UObject* GetAsset() const { return OriginalAsset; }
|
||||||
|
template<class T> T* CastAsset()
|
||||||
|
{
|
||||||
|
if (!CheckAssetIsA(T::StaticClass())) return nullptr;
|
||||||
|
return ::Cast<T>(OriginalAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// When an asset is loaded, an editor is automatically
|
||||||
|
// opened. Get the editor. You must specify the type
|
||||||
|
// that you expect the asset to be, and the type to cast
|
||||||
|
// the editor to. Does not generate errors.
|
||||||
|
//
|
||||||
|
template<class AssetType, class EditorType>
|
||||||
|
EditorType* CastEditor()
|
||||||
|
{
|
||||||
|
if (!CheckAssetIsA(AssetType::StaticClass())) return nullptr;
|
||||||
|
return static_cast<EditorType*>(Editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize empty. You need to call Asset, or walk
|
||||||
|
// a path that starts with an asset.
|
||||||
|
//
|
||||||
|
MCPFetcher() {}
|
||||||
|
|
||||||
|
// Initialize with an object. From there, you can walk
|
||||||
|
// to sub-objects.
|
||||||
|
//
|
||||||
|
MCPFetcher(UObject* O) : Obj(O) {}
|
||||||
|
|
||||||
|
// Print out the documentation for paths, for the LLM.
|
||||||
|
//
|
||||||
|
static void PrintDocs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The Current Object or Pin
|
|
||||||
|
// The Current Object. Only one of these can be non-null.
|
||||||
UObject* Obj = nullptr;
|
UObject* Obj = nullptr;
|
||||||
UEdGraphPin* ResultPin = nullptr;
|
UEdGraphPin* ResultPin = nullptr;
|
||||||
|
|
||||||
// The Starting Asset and the Editor we Opened
|
// The Starting Asset and the Editor we Opened.
|
||||||
UObject* OriginalAsset = nullptr;
|
UObject* OriginalAsset = nullptr;
|
||||||
IAssetEditorInstance* Editor = nullptr;
|
IAssetEditorInstance* Editor = nullptr;
|
||||||
|
|
||||||
@@ -100,12 +138,13 @@ private:
|
|||||||
bool bError = false;
|
bool bError = false;
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
using WalkFunc = MCPFetcher& (MCPFetcher::*)(const FString&);
|
||||||
void SetObj(UObject* InObj);
|
void SetObj(UObject* InObj);
|
||||||
void SetPin(UEdGraphPin* InPin);
|
void SetPin(UEdGraphPin* InPin);
|
||||||
MCPFetcher& SetError();
|
MCPFetcher& SetError();
|
||||||
MCPFetcher& TypeMismatch(const TCHAR* Walker, const TCHAR* Expected);
|
MCPFetcher& TypeMismatch(const TCHAR* Walker, const TCHAR* Expected);
|
||||||
const FWalker* GetWalker(const FString& Key);
|
|
||||||
bool CheckAssetIsA(UClass* StaticClass);
|
bool CheckAssetIsA(UClass* StaticClass);
|
||||||
|
WalkFunc GetWalker(const FString &Step);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> inline UEdGraphPin* MCPFetcher::Cast<UEdGraphPin>()
|
template<> inline UEdGraphPin* MCPFetcher::Cast<UEdGraphPin>()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
// the value's storage. operator-> forwards to the FProperty.
|
// the value's storage. operator-> forwards to the FProperty.
|
||||||
struct MCPProperty
|
struct MCPProperty
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
FProperty* Prop = nullptr;
|
FProperty* Prop = nullptr;
|
||||||
void* Container = nullptr;
|
void* Container = nullptr;
|
||||||
|
|
||||||
@@ -23,4 +24,7 @@ struct MCPProperty
|
|||||||
static TArray<MCPProperty> GetAllSubstring(UObject* Obj, EPropertyFlags Flags, const FString& Substring);
|
static TArray<MCPProperty> GetAllSubstring(UObject* Obj, EPropertyFlags Flags, const FString& Substring);
|
||||||
static TArray<MCPProperty> GetAllExactMatch(UObject* Obj, EPropertyFlags Flags, const FString& Name);
|
static TArray<MCPProperty> GetAllExactMatch(UObject* Obj, EPropertyFlags Flags, const FString& Name);
|
||||||
static MCPProperty GetOneExactMatch(UObject* Obj, EPropertyFlags Flags, const FString& Name);
|
static MCPProperty GetOneExactMatch(UObject* Obj, EPropertyFlags Flags, const FString& Name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void Collect(UObject *Obj, TArray<MCPProperty> &Props, EPropertyFlags Flags);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user