Working on editing materials

This commit is contained in:
2026-03-11 22:03:32 -04:00
parent 0e79b02307
commit 2e058035f3
102 changed files with 428 additions and 463 deletions

View File

@@ -4,12 +4,12 @@
#include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
#include "UObject/PropertyAccessUtil.h"
#include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h"
#include "Engine/World.h"
#include "Materials/Material.h"
#include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "Engine/LevelScriptBlueprint.h"
MCPFetcher& MCPFetcher::SetError(const FString& Msg)
@@ -31,6 +31,19 @@ MCPFetcher& MCPFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expected)
return *this;
}
const TArray<MCPFetcher::FWalker>& MCPFetcher::GetWalkerTable()
{
static const 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 },
// { TEXT("matexp"), TEXT("Get the UMaterialExpression from a UMaterialGraphNode"), &MCPFetcher::MatExp },
};
return Table;
}
MCPFetcher& MCPFetcher::Walk(const FString& Path)
{
if (bError) return *this;
@@ -53,6 +66,8 @@ MCPFetcher& MCPFetcher::Walk(const FString& Path)
Start = 1;
}
const TArray<FWalker>& Walkers = GetWalkerTable();
// Walk each subsequent segment
for (int32 i = Start; i < Segments.Num(); i++)
{
@@ -60,13 +75,16 @@ MCPFetcher& MCPFetcher::Walk(const FString& Path)
if (!Segments[i].Split(TEXT(":"), &Key, &Value))
Key = Segments[i];
if (StrEq(Key, TEXT("graph"))) Graph(Value);
else if (StrEq(Key, TEXT("node"))) Node(Value);
else if (StrEq(Key, TEXT("pin"))) Pin(Value);
else if (StrEq(Key, TEXT("component"))) Component(Value);
else if (StrEq(Key, TEXT("property"))) Property(Value);
else if (StrEq(Key, TEXT("levelblueprint"))) LevelBlueprint();
else
bool bFound = false;
for (const FWalker& W : Walkers)
{
if (!StrEq(Key, W.Key)) continue;
(this->*W.Func)(Value);
bFound = true;
break;
}
if (!bFound)
{
SetError(FString::Printf(TEXT("Unknown walker '%s'"), *Key));
return *this;
@@ -215,30 +233,7 @@ MCPFetcher& MCPFetcher::Component(const FString& Value)
return SetError(FString::Printf(TEXT("Component '%s' not found in %s"), *Value, *BP->GetName()));
}
MCPFetcher& MCPFetcher::Property(const FString& Value)
{
if (bError) return *this;
if (!Obj)
return TypeMismatch(TEXT("property"), TEXT("UObject"));
FProperty* Prop = Obj->GetClass()->FindPropertyByName(FName(*Value));
if (!Prop)
return SetError(FString::Printf(TEXT("Property '%s' not found on %s"), *Value, *Obj->GetClass()->GetName()));
FObjectProperty* ObjProp = CastField<FObjectProperty>(Prop);
if (!ObjProp)
return SetError(FString::Printf(TEXT("Property '%s' is not an object property (type: %s)"), *Value, *Prop->GetCPPType()));
UObject* PropValue = ObjProp->GetObjectPropertyValue(Prop->ContainerPtrToValuePtr<void>(Obj));
if (!PropValue)
return SetError(FString::Printf(TEXT("Property '%s' is null on %s"), *Value, *Obj->GetName()));
SetObj(PropValue);
return *this;
}
MCPFetcher& MCPFetcher::LevelBlueprint()
MCPFetcher& MCPFetcher::LevelBlueprint(const FString& Value)
{
if (bError) return *this;
@@ -256,3 +251,36 @@ MCPFetcher& MCPFetcher::LevelBlueprint()
SetObj(LevelBP);
return *this;
}
MCPFetcher& MCPFetcher::Template()
{
if (bError) return *this;
if (!Obj)
return SetError(TEXT("Template: object is null"));
if (UBlueprint* BP = ::Cast<UBlueprint>(Obj))
{
if (!BP->GeneratedClass)
return SetError(FString::Printf(TEXT("Blueprint '%s' has no GeneratedClass"), *Obj->GetName()));
SetObj(BP->GeneratedClass->GetDefaultObject());
return *this;
}
// Everything else is its own template — no navigation needed.
return *this;
}
MCPFetcher& MCPFetcher::MatExp(const FString& Value)
{
if (bError) return *this;
UMaterialGraphNode* MatNode = ::Cast<UMaterialGraphNode>(Obj);
if (!MatNode)
return TypeMismatch(TEXT("matexp"), TEXT("UMaterialGraphNode"));
if (!MatNode->MaterialExpression)
return SetError(FString::Printf(TEXT("Node '%s' has no MaterialExpression"), *MCPUtils::FormatName(MatNode)));
SetObj(MatNode->MaterialExpression);
return *this;
}