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

Binary file not shown.

View File

@@ -11,14 +11,46 @@
#include "K2Node_CallFunction.h" #include "K2Node_CallFunction.h"
#include "K2Node_FunctionEntry.h" #include "K2Node_FunctionEntry.h"
static FString WrapText(const FString& Text, int32 ColLimit, const FString& Prefix)
{
FString Clean = Text;
Clean.ReplaceInline(TEXT("\r\n"), TEXT("\n"));
TArray<FString> Words;
Clean.ParseIntoArrayWS(Words);
TStringBuilder<1024> Result;
int32 Col = 0;
for (const FString& Word : Words)
{
if (Col > 0 && Col + 1 + Word.Len() > ColLimit)
{
Result.Append(TEXT("\n"));
Col = 0;
}
if (Col == 0)
{
Result.Append(Prefix);
Col = Prefix.Len();
}
else
{
Result.Append(TEXT(" "));
Col += 1;
}
Result.Append(Word);
Col += Word.Len();
}
return Result.ToString();
}
FlxBlueprintExporter::FlxBlueprintExporter(UEdGraph* InGraph) FlxBlueprintExporter::FlxBlueprintExporter(UEdGraph* InGraph)
: Graph(InGraph) : Graph(InGraph)
{ {
SortNodes(); SortNodes();
AssignNodeNames(); EmitLocalVariables();
EmitLocalVariables(); EmitDetails();
EmitNodeList();
EmitGraph(); EmitGraph();
EmitComments();
} }
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
@@ -194,20 +226,11 @@ void FlxBlueprintExporter::SortNodes()
} }
} }
void FlxBlueprintExporter::AssignNodeNames()
{
// Node names are now computed on the fly by FormatNodeName.
}
void FlxBlueprintExporter::EmitNode(UEdGraphNode* Node) void FlxBlueprintExporter::EmitNode(UEdGraphNode* Node)
{ {
if (Node->IsA<UEdGraphNode_Comment>()) if (Node->IsA<UEdGraphNode_Comment>()) return;
{
Output.Appendf(TEXT("\n// %s\n"), *Node->NodeComment);
return;
}
Output.Appendf(TEXT("\nnode %s\n"), *MCPUtils::FormatName(Node)); Output.Appendf(TEXT("\nnode %s: %s\n"), *MCPUtils::FormatName(Node), *MCPUtils::FormatNodeTitle(Node));
// Emit input data pins. // Emit input data pins.
for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Input)) for (UEdGraphPin* Pin : FilterPins(Node, EGPD_Input))
@@ -280,14 +303,50 @@ void FlxBlueprintExporter::EmitGraph()
} }
} }
void FlxBlueprintExporter::EmitNodeList() void FlxBlueprintExporter::EmitDetails()
{ {
for (UEdGraphNode* Node : SortedNodes) for (UEdGraphNode* Node : SortedNodes)
{ {
if (Node->IsA<UK2Node_Knot>()) continue; if (Node->IsA<UK2Node_Knot>()) continue;
if (Node->IsA<UEdGraphNode_Comment>()) continue; if (Node->IsA<UEdGraphNode_Comment>()) continue;
if (Node->IsA<UK2Node_VariableGet>()) continue; if (Node->IsA<UK2Node_VariableGet>()) continue;
Details.Appendf(TEXT("%s = %s\n"), Details.Appendf(TEXT("details %s\n"), *MCPUtils::FormatName(Node));
*MCPUtils::FormatName(Node), *Node->NodeGuid.ToString()); Details.Appendf(TEXT(" pos %d, %d\n"), Node->NodePosX, Node->NodePosY);
}
}
void FlxBlueprintExporter::EmitComments()
{
for (UEdGraphNode* CommentNode : SortedNodes)
{
if (!CommentNode->IsA<UEdGraphNode_Comment>()) continue;
int32 CX = CommentNode->NodePosX;
int32 CY = CommentNode->NodePosY;
int32 CW = CommentNode->NodeWidth;
int32 CH = CommentNode->NodeHeight;
// Emit header.
Output.Append(TEXT("\ncomment:\n"));
// Emit wrapped, indented body.
Output.Append(WrapText(CommentNode->NodeComment, 70, TEXT(" - ")));
Output.Append(TEXT("\n"));
// Find contained nodes.
TArray<FString> ContainedNames;
for (UEdGraphNode* Node : SortedNodes)
{
if (Node->IsA<UEdGraphNode_Comment>()) continue;
int32 NX = Node->NodePosX;
int32 NY = Node->NodePosY;
if (NX >= CX && NY >= CY && NX <= CX + CW && NY <= CY + CH)
ContainedNames.Add(MCPUtils::FormatName(Node));
}
if (ContainedNames.Num() > 0)
{
Output.Appendf(TEXT(" applies to: %s\n"), *FString::Join(ContainedNames, TEXT(", ")));
}
} }
} }

View File

@@ -1,99 +1,45 @@
# Your Goals
We want to do several things. I'll give you * Command-handlers are classes that implement the MCPHandler
the concise list of goals, then I'll circle back interface. The command's json parameters automatically get
and give you the coding standard we're trying injected into the handler's properties using reflection
to achieve. code. Check out a few handlers to see how this works.
- Convert these handlers to use plain-text output
wherever it is practical.
- MCPAssetFinder and MCPFetcher are powerful tools
to retrieve assets and objects. We want to migrate
the code to use these over hand-rolled solutions.
- Get rid of ad-hoc code to calculate object names,
which inevitably results in inconsistent naming.
- To make some of these handlers process batches,
rather than single objects, where it makes sense
to do so.
- To reduce the amount of code that's just passing
error messages around.
- To get rid of UE_LOG calls.
# Our Coding Standards
This is what we're trying to achieve with these goals.
* When searching for uassets, the tool MCPAssetFinder is
often the most precise, concise, and efficient tool.
Please study this API before starting. Using this
tool gives more reliable and more concise code than
hand-rolling code to obtain assets.
* Class MCPFetcher can precisely and easily retrieve objects
of all different kinds using clear, specific identifiers.
It is the best tool when you need the caller to specify a
blueprint, or a graph, or a pin - you name it. It relieves
you of the burden of digging around in unreal's data
structures. It also enforces a naming consistency
across handlers. Please study this API.
* To get the name of an object, there are tons of methods * Class MCPFetcher can precisely and easily retrieve objects
you could call: pin->GetName(), pin->NodeGuid.ToString(), of all different kinds using a 'path'. Study the API
node->GetTitle()... there are *so many* ways to get a of this class, we use it everywhere. It is the best tool
readable label. All of those ways are *NOT ALLOWED*. The when you need the caller to specify a blueprint, or a
only valid way to get a name for an object is using graph, or a pin - you name it.
MCPUtils::FormatName(obj). This is to enforce consistent
naming. FormatName has been designed to produce very * When you want to scan for a list of assets, MCPAssets
clear, very readable, and highly unique identifiers. is the best tool. This wraps Unreal's asset database
More importantly, if one tool outputs a name, a different in a convenient interface. Please study this API.
tool will accept that name, because both tools use the
same naming scheme. * The only valid way to get a name for an object is using
MCPUtils::FormatName(obj). We don't allow the use of
pin->GetName, or node->GetTitle, or any other name-fetching
routine. Using only MCPUtils::FormatName guarantees
consistency: that means, names output by one tool can
be parsed by a different tool.
* To check whether a string matches an object's name, * To check whether a string matches an object's name,
there's only one valid way to do that as well: using there's only one valid way to do that as well: using
bool MCPUtils::Identifies(Name, Obj). Don't compare bool MCPUtils::Identifies(Name, Obj).
the name yourself: you might get the case-sensitivity
wrong, you might forget to ignore trailing whitespace,
there are too many things that could go wrong. We've
provided MCPUtils::Identifies, which does it right
every time, for every kind of object.
* Concise output is better. The output of these handlers * Concise output is better. The output of these handlers
will primarily be consumed by LLMs with finite context will primarily be consumed by LLMs with finite context
windows. Plain-text handlers beat json handlers for windows. Avoid sending information the caller didn't ask
minimizing tokens: read the API for MCPHandler.h to learn for. Don't echo the command parameters: the caller knows
how to create a plain text handler. Avoid sending what parameters he sent. Don't make things unnecessarily
information the caller didn't ask for. Don't echo the verbose: "type=int varname=x" can be shortened to "int x."
command parameters: the caller knows what parameters he
sent. Don't make things unnecessarily verbose:
"type=int varname=x" can be shortened to "int x."
Generate output in a form that *you* would want to Generate output in a form that *you* would want to
consume. consume.
* It's really important to send good error messages back to * You can pass the output StringBuilder directly into
the caller. Every handler has a second parameter, the MCPFetcher and MCPAssets. If you do, these will automatically
"output device", which is used to send data back to the generate good error messages. If either of these classes
caller. The "output device" can either be a stringbuilder, returns 'false', you don't need to generate an error
or a json tree. Our two core tools, MCPFetcher and message: it's already been done. Any other routine that
MCPAssetFinder, have powerful error handling built in: if accepts MCPErrorCallback can do the same.
you give them a reference to the output device, they
will send error messages directly back to the caller
without your intervention. This is bulletproof.
Study class MCPErrorCallback to see how this works: any
function that takes MCPErrorCallback can put errors
directly into an "output device".
* If the output device of your handler is a shared ptr
to a json tree, you might see code that passes &*Json to
an MCPErrorCallback. That's legacy: it used to be necessary
to convert the shared pointer into a regular pointer.
Now the MCPErrorCallback can accept the shared pointer
directly.
* It's good for handlers to do operations in batches, * It's good for handlers to do operations in batches,
where possible. SpawnNodes is better than SpawnNode. where possible. SpawnNodes is better than SpawnNode.
@@ -108,10 +54,9 @@ This is what we're trying to achieve with these goals.
Better to report problems via the response. Please remove Better to report problems via the response. Please remove
UE_LOG calls in handlers. UE_LOG calls in handlers.
* In addition to refactoring some handlers, we'd like you * When you're going to edit something, it's important to
to make some notes in a markdown file. The markdown mark things dirty. There's a very powerful tool for that:
file should have the name UMCPHandler_XXX.Notes.md. MCPUtils::PreEdit and MCPUtils::PostEdit, which can also
Tell us what you think is good about the handler, what be accessed through MCPFetcher::PreEdit and PostEdit.
needs more work, and areas where you weren't entirely These routines are very careful about marking everything
confident about what to do, so you acted conservatively. dirty, so you don't have to worry about it.
If there's more to do, we'd like to know.

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddMaterialExpression : public UObject, public IMCPHandler class UMCPHandler_AddMaterialExpression : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -36,7 +36,7 @@ struct FConnectMaterialPinsEntry
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ConnectMaterialExpressionPins : public UObject, public IMCPHandler class UMCPHandler_ConnectMaterialExpressionPins : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteMaterialExpression : public UObject, public IMCPHandler class UMCPHandler_DeleteMaterialExpression : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -30,7 +30,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DescribeMaterialInEnglish : public UObject, public IMCPHandler class UMCPHandler_DescribeMaterialInEnglish : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -19,7 +19,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DisconnectMaterialExpressionPin : public UObject, public IMCPHandler class UMCPHandler_DisconnectMaterialExpressionPin : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -21,7 +21,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpMaterial : public UObject, public IMCPHandler class UMCPHandler_DumpMaterial : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -29,7 +29,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpMaterialFunction : public UObject, public IMCPHandler class UMCPHandler_DumpMaterialFunction : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchWithinMaterials : public UObject, public IMCPHandler class UMCPHandler_SearchWithinMaterials : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialExpressionPosition : public UObject, public IMCPHandler class UMCPHandler_SetMaterialExpressionPosition : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -26,7 +26,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialExpressionProperty : public UObject, public IMCPHandler class UMCPHandler_SetMaterialExpressionProperty : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -19,7 +19,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddAnimStateToMachine : public UObject, public IMCPHandler class UMCPHandler_AddAnimStateToMachine : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddAnimStateTransition : public UObject, public IMCPHandler class UMCPHandler_AddAnimStateTransition : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddBlueprintComponent : public UObject, public IMCPHandler class UMCPHandler_AddBlueprintComponent : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddBlueprintInterface : public UObject, public IMCPHandler class UMCPHandler_AddBlueprintInterface : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddBlueprintVariable : public UObject, public IMCPHandler class UMCPHandler_AddBlueprintVariable : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -29,7 +29,7 @@ struct FDispatcherParamEntry
FString Type; FString Type;
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddEventDispatcher : public UObject, public IMCPHandler class UMCPHandler_AddEventDispatcher : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -18,7 +18,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddFunctionParameter : public UObject, public IMCPHandler class UMCPHandler_AddFunctionParameter : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_AddStructField : public UObject, public IMCPHandler class UMCPHandler_AddStructField : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_BackupAsset : public UObject, public IMCPHandler class UMCPHandler_BackupAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ChangeBlueprintVariableType : public UObject, public IMCPHandler class UMCPHandler_ChangeBlueprintVariableType : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -18,7 +18,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ChangeFunctionParameterType : public UObject, public IMCPHandler class UMCPHandler_ChangeFunctionParameterType : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -19,7 +19,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ChangeStructNodeType : public UObject, public IMCPHandler class UMCPHandler_ChangeStructNodeType : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// Pre-flight check: can two pins be connected? // Pre-flight check: can two pins be connected?
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CheckPinConnectionCompatibility : public UObject, public IMCPHandler class UMCPHandler_CheckPinConnectionCompatibility : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CompileBlueprint : public UObject, public IMCPHandler class UMCPHandler_CompileBlueprint : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CompileMaterial : public UObject, public IMCPHandler class UMCPHandler_CompileMaterial : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -26,7 +26,7 @@ struct FConnectPinsEntry
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ConnectPins : public UObject, public IMCPHandler class UMCPHandler_ConnectPins : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateAnimBlueprintAsset : public UObject, public IMCPHandler class UMCPHandler_CreateAnimBlueprintAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateBlendSpaceAsset : public UObject, public IMCPHandler class UMCPHandler_CreateBlendSpaceAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateBlueprintAsset : public UObject, public IMCPHandler class UMCPHandler_CreateBlueprintAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateBlueprintGraph : public UObject, public IMCPHandler class UMCPHandler_CreateBlueprintGraph : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateEnumAsset : public UObject, public IMCPHandler class UMCPHandler_CreateEnumAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateMaterialAsset : public UObject, public IMCPHandler class UMCPHandler_CreateMaterialAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateMaterialFunctionAsset : public UObject, public IMCPHandler class UMCPHandler_CreateMaterialFunctionAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateMaterialInstanceAsset : public UObject, public IMCPHandler class UMCPHandler_CreateMaterialInstanceAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -29,7 +29,7 @@ struct FStructPropertyEntry
FString Type; FString Type;
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_CreateStructAsset : public UObject, public IMCPHandler class UMCPHandler_CreateStructAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteAsset : public UObject, public IMCPHandler class UMCPHandler_DeleteAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteBlueprintGraph : public UObject, public IMCPHandler class UMCPHandler_DeleteBlueprintGraph : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DeleteNodeFromGraph : public UObject, public IMCPHandler class UMCPHandler_DeleteNodeFromGraph : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DiffTwoBlueprints : public UObject, public IMCPHandler class UMCPHandler_DiffTwoBlueprints : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -26,7 +26,7 @@ struct FDisconnectPinEntry
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DisconnectPins : public UObject, public IMCPHandler class UMCPHandler_DisconnectPins : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpBlueprint : public UObject, public IMCPHandler class UMCPHandler_DumpBlueprint : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpGraphs : public UObject, public IMCPHandler class UMCPHandler_DumpGraphs : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -19,7 +19,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpMaterialInstanceParameters : public UObject, public IMCPHandler class UMCPHandler_DumpMaterialInstanceParameters : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -11,7 +11,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DumpProperties : public UObject, public IMCPHandler class UMCPHandler_DumpProperties : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()
@@ -26,6 +26,9 @@ public:
UPROPERTY(meta=(Optional, Description="Truncate values to 80 characters (default true)")) UPROPERTY(meta=(Optional, Description="Truncate values to 80 characters (default true)"))
bool Truncate = 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 virtual FString GetDescription() const override
{ {
return TEXT("List all blueprint-visible properties on an object resolved via MCPFetcher path, " return TEXT("List all blueprint-visible properties on an object resolved via MCPFetcher path, "
@@ -34,16 +37,12 @@ public:
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{ {
// Resolve the path to an object. // Resolve the path to an object and get its editable template.
MCPFetcher F(Result); MCPFetcher F(Result);
UObject* Obj = F.Walk(Path).Cast<UObject>(); UObject* Template = F.Walk(Path).Template().Cast<UObject>();
if (!Obj) return;
// Get the editable template (e.g. Blueprint → CDO).
UObject* Template = MCPUtils::GetEditableTemplate(Obj, Result);
if (!Template) return; if (!Template) return;
TArray<FProperty*> Props = MCPUtils::BlueprintVisibleProperties(Template, Query); TArray<FProperty*> Props = MCPUtils::SearchProperties(Template, Query, CPF_Edit, Local);
UStruct* CurrentOwner = nullptr; UStruct* CurrentOwner = nullptr;
for (FProperty* Prop : Props) for (FProperty* Prop : Props)
@@ -63,7 +62,7 @@ public:
if (Truncate && (ValueStr.Len() > 80)) if (Truncate && (ValueStr.Len() > 80))
ValueStr = ValueStr.Left(80) + TEXT("..."); ValueStr = ValueStr.Left(80) + TEXT("...");
bool bEditable = Prop->HasAnyPropertyFlags(CPF_Edit); bool bEditable = !Prop->HasAnyPropertyFlags(CPF_EditConst);
Result.Appendf(TEXT(" %s %s %s = %s\n"), Result.Appendf(TEXT(" %s %s %s = %s\n"),
bEditable ? TEXT("editable") : TEXT("readonly"), bEditable ? TEXT("editable") : TEXT("readonly"),
*MCPUtils::FormatPropertyType(Prop), *MCPUtils::FormatPropertyType(Prop),

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_DuplicateNodesInGraph : public UObject, public IMCPHandler class UMCPHandler_DuplicateNodesInGraph : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -11,7 +11,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_FindAssetReferences : public UObject, public IMCPHandler class UMCPHandler_FindAssetReferences : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_FindMaterialReferences : public UObject, public IMCPHandler class UMCPHandler_FindMaterialReferences : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -12,7 +12,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_GetNodeComment : public UObject, public IMCPHandler class UMCPHandler_GetNodeComment : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// HandleGetPinInfo — detailed information about a specific pin // HandleGetPinInfo — detailed information about a specific pin
// ============================================================ // ============================================================
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_GetPinDetails : public UObject, public IMCPHandler class UMCPHandler_GetPinDetails : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListAnimSlotNames : public UObject, public IMCPHandler class UMCPHandler_ListAnimSlotNames : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListAnimSyncGroups : public UObject, public IMCPHandler class UMCPHandler_ListAnimSyncGroups : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListBlueprintAssets : public UObject, public IMCPHandler class UMCPHandler_ListBlueprintAssets : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListBlueprintComponents : public UObject, public IMCPHandler class UMCPHandler_ListBlueprintComponents : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -12,7 +12,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListBlueprintInterfaces : public UObject, public IMCPHandler class UMCPHandler_ListBlueprintInterfaces : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -10,7 +10,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListClassProperties : public UObject, public IMCPHandler class UMCPHandler_ListClassProperties : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -17,7 +17,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListEventDispatchers : public UObject, public IMCPHandler class UMCPHandler_ListEventDispatchers : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -10,7 +10,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ListOpenAssetEditors : public UObject, public IMCPHandler class UMCPHandler_ListOpenAssetEditors : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -11,7 +11,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_OpenAssetEditor : public UObject, public IMCPHandler class UMCPHandler_OpenAssetEditor : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RefreshAllNodesInGraph : public UObject, public IMCPHandler class UMCPHandler_RefreshAllNodesInGraph : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveAnimStateFromMachine : public UObject, public IMCPHandler class UMCPHandler_RemoveAnimStateFromMachine : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveBlueprintComponent : public UObject, public IMCPHandler class UMCPHandler_RemoveBlueprintComponent : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveBlueprintInterface : public UObject, public IMCPHandler class UMCPHandler_RemoveBlueprintInterface : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveBlueprintVariable : public UObject, public IMCPHandler class UMCPHandler_RemoveBlueprintVariable : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -16,7 +16,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveFunctionParameter : public UObject, public IMCPHandler class UMCPHandler_RemoveFunctionParameter : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RemoveStructField : public UObject, public IMCPHandler class UMCPHandler_RemoveStructField : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RenameAsset : public UObject, public IMCPHandler class UMCPHandler_RenameAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RenameBlueprintGraph : public UObject, public IMCPHandler class UMCPHandler_RenameBlueprintGraph : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ReparentBlueprint : public UObject, public IMCPHandler class UMCPHandler_ReparentBlueprint : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -14,7 +14,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ReparentMaterialInstance : public UObject, public IMCPHandler class UMCPHandler_ReparentMaterialInstance : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -18,7 +18,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_ReplaceFunctionCallsInBlueprint : public UObject, public IMCPHandler class UMCPHandler_ReplaceFunctionCallsInBlueprint : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_RestoreAsset : public UObject, public IMCPHandler class UMCPHandler_RestoreAsset : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -11,7 +11,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchAssets : public UObject, public IMCPHandler class UMCPHandler_SearchAssets : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchSpawnableNodeTypes : public UObject, public IMCPHandler class UMCPHandler_SearchSpawnableNodeTypes : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -31,7 +31,7 @@
// HandleSearchByType — find all usages of a type across blueprints // HandleSearchByType — find all usages of a type across blueprints
// ============================================================ // ============================================================
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchTypeUsageInBlueprints : public UObject, public IMCPHandler class UMCPHandler_SearchTypeUsageInBlueprints : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// HandleListClasses — discover available UClasses // HandleListClasses — discover available UClasses
// ============================================================ // ============================================================
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchUnrealClasses : public UObject, public IMCPHandler class UMCPHandler_SearchUnrealClasses : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -21,7 +21,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SearchWithinBlueprints : public UObject, public IMCPHandler class UMCPHandler_SearchWithinBlueprints : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -20,7 +20,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetAnimStateAnimation : public UObject, public IMCPHandler class UMCPHandler_SetAnimStateAnimation : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -23,7 +23,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetAnimStateBlendSpace : public UObject, public IMCPHandler class UMCPHandler_SetAnimStateBlendSpace : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetAnimTransitionRule : public UObject, public IMCPHandler class UMCPHandler_SetAnimTransitionRule : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -29,7 +29,7 @@ struct FBlendSpaceSampleEntry
float Y = 0.0f; float Y = 0.0f;
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetBlendSpaceSamplePoints : public UObject, public IMCPHandler class UMCPHandler_SetBlendSpaceSamplePoints : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetBlueprintVariableMetadata : public UObject, public IMCPHandler class UMCPHandler_SetBlueprintVariableMetadata : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -15,7 +15,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetClassDefaultValue : public UObject, public IMCPHandler class UMCPHandler_SetClassDefaultValue : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -19,7 +19,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialInstanceParameter : public UObject, public IMCPHandler class UMCPHandler_SetMaterialInstanceParameter : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetMaterialProperty : public UObject, public IMCPHandler class UMCPHandler_SetMaterialProperty : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -13,7 +13,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetNodeComment : public UObject, public IMCPHandler class UMCPHandler_SetNodeComment : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -30,7 +30,7 @@ struct FMoveNodeEntry
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetNodePositions : public UObject, public IMCPHandler class UMCPHandler_SetNodePositions : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -26,7 +26,7 @@ struct FSetPinDefaultEntry
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetPinDefaultValues : public UObject, public IMCPHandler class UMCPHandler_SetPinDefaultValues : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()
@@ -45,7 +45,6 @@ public:
int32 SuccessCount = 0; int32 SuccessCount = 0;
int32 TotalCount = Pins.Array.Num(); int32 TotalCount = Pins.Array.Num();
TSet<UEdGraphNode*> ModifiedNodes; TSet<UEdGraphNode*> ModifiedNodes;
TSet<UBlueprint*> ModifiedBlueprints;
for (const TSharedPtr<FJsonValue>& PinVal : Pins.Array) for (const TSharedPtr<FJsonValue>& PinVal : Pins.Array)
{ {
@@ -67,19 +66,13 @@ public:
const UEdGraphSchema* Schema = Node->GetGraph()->GetSchema(); const UEdGraphSchema* Schema = Node->GetGraph()->GetSchema();
if (Schema) if (Schema)
{ Schema->TrySetDefaultValue(*Pin, Entry.Value);
FString ValidationError = Schema->IsPinDefaultValid(Pin, Entry.Value, nullptr, FText::GetEmpty()); else
if (!ValidationError.IsEmpty()) Pin->DefaultValue = Entry.Value;
{
Result.Appendf(TEXT("error: Invalid value for %s: %s\n"), *MCPUtils::FormatName(Pin), *ValidationError);
continue;
}
}
Pin->DefaultValue = Entry.Value;
SuccessCount++; SuccessCount++;
ModifiedNodes.Add(Node); ModifiedNodes.Add(Node);
ModifiedBlueprints.Add(FBlueprintEditorUtils::FindBlueprintForNodeChecked(Node)); F.PostEdit();
} }
for (UEdGraphNode* Node : ModifiedNodes) for (UEdGraphNode* Node : ModifiedNodes)
@@ -87,11 +80,6 @@ public:
Node->ReconstructNode(); Node->ReconstructNode();
} }
for (UBlueprint* BP : ModifiedBlueprints)
{
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
Result.Appendf(TEXT("Set %d/%d pin defaults.\n"), SuccessCount, TotalCount); Result.Appendf(TEXT("Set %d/%d pin defaults.\n"), SuccessCount, TotalCount);
} }
}; };

View File

@@ -11,7 +11,7 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SetProperties : public UObject, public IMCPHandler class UMCPHandler_SetProperties : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()
@@ -31,13 +31,9 @@ public:
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{ {
// Resolve the path to an object. // Resolve the path to an object and get its editable template.
MCPFetcher F(Result); MCPFetcher F(Result);
UObject* Obj = F.Walk(Path).Cast<UObject>(); UObject* Template = F.Walk(Path).Template().Cast<UObject>();
if (!Obj) return;
// Get the editable template (e.g. Blueprint → CDO).
UObject* Template = MCPUtils::GetEditableTemplate(Obj, Result);
if (!Template) return; if (!Template) return;
if (!Properties.Json || Properties.Json->Values.Num() == 0) if (!Properties.Json || Properties.Json->Values.Num() == 0)
@@ -67,7 +63,7 @@ public:
} }
// Apply all changes in a single Pre/PostEditChange bracket. // Apply all changes in a single Pre/PostEditChange bracket.
Template->PreEditChange(nullptr); F.PreEdit();
int32 SuccessCount = 0; int32 SuccessCount = 0;
for (const auto& Pair : Properties.Json->Values) for (const auto& Pair : Properties.Json->Values)
@@ -86,11 +82,10 @@ public:
SuccessCount++; SuccessCount++;
} }
Template->PostEditChange(); F.PostEdit();
// Save. // Save.
Template->MarkPackageDirty(); bool bSaved = MCPUtils::SaveGenericPackage(Template);
bool bSaved = MCPUtils::SaveGenericPackage(Obj);
Result.Appendf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num()); Result.Appendf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
if (!bSaved) if (!bSaved)

View File

@@ -2,10 +2,11 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "UMCPHandler_ShowCommands.generated.h" #include "UMCPHandler_ShowCommands.generated.h"
UCLASS() UCLASS(meta=(Group="Documentation"))
class UMCPHandler_ShowCommands : public UObject, public IMCPHandler class UMCPHandler_ShowCommands : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()
@@ -22,34 +23,71 @@ public:
return TEXT("List all available commands with their descriptions."); return TEXT("List all available commands with their descriptions.");
} }
void EmitGroup(const FString& GroupName, const TArray<UClass*>& Classes, FStringBuilderBase& Result)
{
Result.Appendf(TEXT("\n=== %s ===\n\n"), *GroupName);
for (UClass* Class : Classes)
{
if (Verbose)
{
MCPUtils::FormatCommandHelp(Class, Result);
continue;
}
Result.Append(MCPUtils::GetToolName(Class));
Result.Append(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(Class, EFieldIterationFlags::None); PropIt; ++PropIt)
{
if (!bFirst) Result.Append(TEXT(","));
bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) Result.Append(TEXT("?"));
Result.Append(MCPUtils::FormatPropertyType(*PropIt));
Result.Append(TEXT(" "));
Result.Append(MCPUtils::PropertyNameToJsonKey(PropIt->GetName()));
}
Result.Append(TEXT(")\n"));
}
}
virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override virtual void Handle(const FJsonObject* Json, FStringBuilderBase& Result) override
{ {
FString QueryLower = Query.ToLower(); FString QueryLower = Query.ToLower();
// Group handlers by their Group metadata.
TMap<FString, TArray<UClass*>> Groups;
for (UClass* Class : MCPUtils::CollectHandlerClasses()) for (UClass* Class : MCPUtils::CollectHandlerClasses())
{ {
FString ToolName = MCPUtils::GetToolName(Class); FString ToolName = MCPUtils::GetToolName(Class);
if (!ToolName.ToLower().Contains(QueryLower)) if (!ToolName.ToLower().Contains(QueryLower))
continue; continue;
FString Group = Class->GetMetaData(TEXT("Group"));
if (Verbose) if (Group.IsEmpty()) Group = TEXT("Unclassified");
{ Groups.FindOrAdd(Group).Add(Class);
MCPUtils::FormatCommandHelp(Class, Result);
}
else
{
Result.Append(MCPUtils::GetToolName(Class));
Result.Append(TEXT("("));
bool bFirst = true;
for (TFieldIterator<FProperty> PropIt(Class, EFieldIterationFlags::None); PropIt; ++PropIt)
{
if (!bFirst) Result.Append(TEXT(","));
bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) Result.Append(TEXT("?"));
Result.Append(MCPUtils::PropertyNameToJsonKey(PropIt->GetName()));
}
Result.Append(TEXT(")\n"));
}
} }
// Emit high-priority groups first, in order.
static const TCHAR* HighPriority[] = { TEXT("Documentation") };
for (const TCHAR* HP : HighPriority)
{
TArray<UClass*> Classes;
if (Groups.RemoveAndCopyValue(HP, Classes))
EmitGroup(HP, Classes, Result);
}
// Emit remaining groups.
for (const auto& Pair : Groups)
EmitGroup(Pair.Key, Pair.Value, Result);
// Append Path documentation.
Result.Append(TEXT("\n"));
Result.Append(TEXT("Some commands take a Path parameter. A Path starts with an asset\n"));
Result.Append(TEXT("package path (e.g. /Game/Widgets/WB_Hotkeys), followed by zero or\n"));
Result.Append(TEXT("more comma-separated steps that navigate into the asset:\n"));
Result.Append(TEXT("\n"));
for (const MCPFetcher::FWalker& W : MCPFetcher::GetWalkerTable())
{
Result.Appendf(TEXT(" %s — %s\n"), W.Key, W.Description);
}
Result.Append(TEXT("\nExample: /Game/Widgets/WB_Hotkeys,graph:EventGraph,node:Self_Reference_03,pin:Result\n"));
} }
}; };

View File

@@ -32,7 +32,7 @@ struct FSpawnNodeEntry
}; };
UCLASS() UCLASS(meta=(Group="Unclassified"))
class UMCPHandler_SpawnNodes : public UObject, public IMCPHandler class UMCPHandler_SpawnNodes : public UObject, public IMCPHandler
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@@ -4,12 +4,12 @@
#include "EdGraph/EdGraph.h" #include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
#include "UObject/PropertyAccessUtil.h"
#include "Engine/SimpleConstructionScript.h" #include "Engine/SimpleConstructionScript.h"
#include "Engine/SCS_Node.h" #include "Engine/SCS_Node.h"
#include "Engine/World.h" #include "Engine/World.h"
#include "Materials/Material.h" #include "Materials/Material.h"
#include "MaterialGraph/MaterialGraph.h" #include "MaterialGraph/MaterialGraph.h"
#include "MaterialGraph/MaterialGraphNode.h"
#include "Engine/LevelScriptBlueprint.h" #include "Engine/LevelScriptBlueprint.h"
MCPFetcher& MCPFetcher::SetError(const FString& Msg) MCPFetcher& MCPFetcher::SetError(const FString& Msg)
@@ -31,6 +31,19 @@ MCPFetcher& MCPFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expected)
return *this; 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) MCPFetcher& MCPFetcher::Walk(const FString& Path)
{ {
if (bError) return *this; if (bError) return *this;
@@ -53,6 +66,8 @@ MCPFetcher& MCPFetcher::Walk(const FString& Path)
Start = 1; Start = 1;
} }
const TArray<FWalker>& Walkers = GetWalkerTable();
// Walk each subsequent segment // Walk each subsequent segment
for (int32 i = Start; i < Segments.Num(); i++) 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)) if (!Segments[i].Split(TEXT(":"), &Key, &Value))
Key = Segments[i]; Key = Segments[i];
if (StrEq(Key, TEXT("graph"))) Graph(Value); bool bFound = false;
else if (StrEq(Key, TEXT("node"))) Node(Value); for (const FWalker& W : Walkers)
else if (StrEq(Key, TEXT("pin"))) Pin(Value); {
else if (StrEq(Key, TEXT("component"))) Component(Value); if (!StrEq(Key, W.Key)) continue;
else if (StrEq(Key, TEXT("property"))) Property(Value); (this->*W.Func)(Value);
else if (StrEq(Key, TEXT("levelblueprint"))) LevelBlueprint(); bFound = true;
else break;
}
if (!bFound)
{ {
SetError(FString::Printf(TEXT("Unknown walker '%s'"), *Key)); SetError(FString::Printf(TEXT("Unknown walker '%s'"), *Key));
return *this; 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())); return SetError(FString::Printf(TEXT("Component '%s' not found in %s"), *Value, *BP->GetName()));
} }
MCPFetcher& MCPFetcher::Property(const FString& Value) MCPFetcher& MCPFetcher::LevelBlueprint(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()
{ {
if (bError) return *this; if (bError) return *this;
@@ -256,3 +251,36 @@ MCPFetcher& MCPFetcher::LevelBlueprint()
SetObj(LevelBP); SetObj(LevelBP);
return *this; 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;
}

View File

@@ -5,7 +5,6 @@
#include "Handlers/UMCPHandler_AddBlueprintVariable.h" #include "Handlers/UMCPHandler_AddBlueprintVariable.h"
#include "Handlers/UMCPHandler_AddEventDispatcher.h" #include "Handlers/UMCPHandler_AddEventDispatcher.h"
#include "Handlers/UMCPHandler_AddFunctionParameter.h" #include "Handlers/UMCPHandler_AddFunctionParameter.h"
#include "Handlers/UMCPHandler_AddMaterialExpression.h"
#include "Handlers/UMCPHandler_AddStructField.h" #include "Handlers/UMCPHandler_AddStructField.h"
#include "Handlers/UMCPHandler_BackupAsset.h" #include "Handlers/UMCPHandler_BackupAsset.h"
#include "Handlers/UMCPHandler_ChangeBlueprintVariableType.h" #include "Handlers/UMCPHandler_ChangeBlueprintVariableType.h"
@@ -15,7 +14,6 @@
#include "Handlers/UMCPHandler_CompileBlueprint.h" #include "Handlers/UMCPHandler_CompileBlueprint.h"
#include "Handlers/UMCPHandler_CompileMaterial.h" #include "Handlers/UMCPHandler_CompileMaterial.h"
#include "Handlers/UMCPHandler_ConnectPins.h" #include "Handlers/UMCPHandler_ConnectPins.h"
#include "Handlers/UMCPHandler_ConnectMaterialExpressionPins.h"
#include "Handlers/UMCPHandler_CreateAnimBlueprintAsset.h" #include "Handlers/UMCPHandler_CreateAnimBlueprintAsset.h"
#include "Handlers/UMCPHandler_CreateBlendSpaceAsset.h" #include "Handlers/UMCPHandler_CreateBlendSpaceAsset.h"
#include "Handlers/UMCPHandler_CreateBlueprintAsset.h" #include "Handlers/UMCPHandler_CreateBlueprintAsset.h"
@@ -27,17 +25,12 @@
#include "Handlers/UMCPHandler_CreateStructAsset.h" #include "Handlers/UMCPHandler_CreateStructAsset.h"
#include "Handlers/UMCPHandler_DeleteAsset.h" #include "Handlers/UMCPHandler_DeleteAsset.h"
#include "Handlers/UMCPHandler_DeleteBlueprintGraph.h" #include "Handlers/UMCPHandler_DeleteBlueprintGraph.h"
#include "Handlers/UMCPHandler_DeleteMaterialExpression.h"
#include "Handlers/UMCPHandler_DeleteNodeFromGraph.h" #include "Handlers/UMCPHandler_DeleteNodeFromGraph.h"
#include "Handlers/UMCPHandler_DescribeMaterialInEnglish.h"
#include "Handlers/UMCPHandler_DiffTwoBlueprints.h" #include "Handlers/UMCPHandler_DiffTwoBlueprints.h"
#include "Handlers/UMCPHandler_DisconnectPins.h" #include "Handlers/UMCPHandler_DisconnectPins.h"
#include "Handlers/UMCPHandler_DisconnectMaterialExpressionPin.h"
#include "Handlers/UMCPHandler_DumpBlueprint.h" #include "Handlers/UMCPHandler_DumpBlueprint.h"
#include "Handlers/UMCPHandler_DumpProperties.h" #include "Handlers/UMCPHandler_DumpProperties.h"
#include "Handlers/UMCPHandler_DumpGraphs.h" #include "Handlers/UMCPHandler_DumpGraphs.h"
#include "Handlers/UMCPHandler_DumpMaterial.h"
#include "Handlers/UMCPHandler_DumpMaterialFunction.h"
#include "Handlers/UMCPHandler_DumpMaterialInstanceParameters.h" #include "Handlers/UMCPHandler_DumpMaterialInstanceParameters.h"
#include "Handlers/UMCPHandler_DuplicateNodesInGraph.h" #include "Handlers/UMCPHandler_DuplicateNodesInGraph.h"
#include "Handlers/UMCPHandler_FindAssetReferences.h" #include "Handlers/UMCPHandler_FindAssetReferences.h"
@@ -71,15 +64,12 @@
#include "Handlers/UMCPHandler_SearchTypeUsageInBlueprints.h" #include "Handlers/UMCPHandler_SearchTypeUsageInBlueprints.h"
#include "Handlers/UMCPHandler_SearchUnrealClasses.h" #include "Handlers/UMCPHandler_SearchUnrealClasses.h"
#include "Handlers/UMCPHandler_SearchWithinBlueprints.h" #include "Handlers/UMCPHandler_SearchWithinBlueprints.h"
#include "Handlers/UMCPHandler_SearchWithinMaterials.h"
#include "Handlers/UMCPHandler_SetAnimStateAnimation.h" #include "Handlers/UMCPHandler_SetAnimStateAnimation.h"
#include "Handlers/UMCPHandler_SetAnimStateBlendSpace.h" #include "Handlers/UMCPHandler_SetAnimStateBlendSpace.h"
#include "Handlers/UMCPHandler_SetAnimTransitionRule.h" #include "Handlers/UMCPHandler_SetAnimTransitionRule.h"
#include "Handlers/UMCPHandler_SetBlendSpaceSamplePoints.h" #include "Handlers/UMCPHandler_SetBlendSpaceSamplePoints.h"
#include "Handlers/UMCPHandler_SetBlueprintVariableMetadata.h" #include "Handlers/UMCPHandler_SetBlueprintVariableMetadata.h"
#include "Handlers/UMCPHandler_SetClassDefaultValue.h" #include "Handlers/UMCPHandler_SetClassDefaultValue.h"
#include "Handlers/UMCPHandler_SetMaterialExpressionPosition.h"
#include "Handlers/UMCPHandler_SetMaterialExpressionProperty.h"
#include "Handlers/UMCPHandler_SetMaterialInstanceParameter.h" #include "Handlers/UMCPHandler_SetMaterialInstanceParameter.h"
#include "Handlers/UMCPHandler_SetMaterialProperty.h" #include "Handlers/UMCPHandler_SetMaterialProperty.h"
#include "Handlers/UMCPHandler_SetNodeComment.h" #include "Handlers/UMCPHandler_SetNodeComment.h"

View File

@@ -125,11 +125,6 @@ void MCPUtils::SanitizeNameInPlace(FString &Name)
if (Name.IsEmpty()) Name = TEXT("_"); if (Name.IsEmpty()) Name = TEXT("_");
} }
void MCPUtils::AppendNumericSuffix(FString &Name, int32 N)
{
if (N > 0)
Name += FString::Printf(TEXT("_%d"), N - 1);
}
FString MCPUtils::FormatName(const UWorld *World) FString MCPUtils::FormatName(const UWorld *World)
{ {
@@ -155,14 +150,7 @@ FString MCPUtils::FormatName(const UEdGraph *Graph)
FString MCPUtils::FormatName(const UEdGraphNode* Node) FString MCPUtils::FormatName(const UEdGraphNode* Node)
{ {
// Sanitized first line of the node title. return Node->GetName();
FString Title = Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
int32 NewlineIdx;
if (Title.FindChar(TEXT('\n'), NewlineIdx))
Title.LeftInline(NewlineIdx);
SanitizeNameInPlace(Title);
AppendNumericSuffix(Title, Node->GetFName().GetNumber());
return Title;
} }
FString MCPUtils::FormatName(const UEdGraphPin *Pin) FString MCPUtils::FormatName(const UEdGraphPin *Pin)
@@ -259,99 +247,12 @@ FString MCPUtils::FormatName(const FProperty *Prop)
return Prop->GetName(); return Prop->GetName();
} }
bool MCPUtils::Identifies(const FString &Name, const FBPVariableDescription &Var)
{
return FormatName(Var).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UStruct *Struct)
{
return FormatName(Struct).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UMaterial *Material)
{
return FormatName(Material).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UMaterialInstance *MaterialInstance)
{
return FormatName(MaterialInstance).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UMaterialFunction *MaterialFunction)
{
return FormatName(MaterialFunction).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UMaterialExpression *Expression)
{
return FormatName(Expression).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UStaticMesh *Mesh)
{
return FormatName(Mesh).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const USkeletalMesh *Mesh)
{
return FormatName(Mesh).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UAnimSequence *Anim)
{
return FormatName(Anim).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UBlendSpace *BlendSpace)
{
return FormatName(BlendSpace).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UTexture *Texture)
{
return FormatName(Texture).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UScriptStruct *Struct)
{
return FormatName(Struct).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UEnum *Enum)
{
return FormatName(Enum).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const FProperty *Prop)
{
return FormatName(Prop).Equals(Name, ESearchCase::IgnoreCase);
}
// ============================================================ // ============================================================
// Identifies // Identifies
// ============================================================ // ============================================================
bool MCPUtils::Identifies(const FString &Name, const UWorld *World) // Most types are handled by the template in MCPUtils.h.
{ // UEdGraphNode also matches by GUID:
return FormatName(World).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UBlueprint *BP)
{
return FormatName(BP).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UActorComponent *C)
{
return FormatName(C).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UEdGraph *Graph)
{
return FormatName(Graph).Equals(Name, ESearchCase::IgnoreCase);
}
bool MCPUtils::Identifies(const FString &Name, const UEdGraphNode* Node) bool MCPUtils::Identifies(const FString &Name, const UEdGraphNode* Node)
{ {
@@ -360,15 +261,9 @@ bool MCPUtils::Identifies(const FString &Name, const UEdGraphNode* Node)
return FormatName(Node).Equals(Name, ESearchCase::IgnoreCase); return FormatName(Node).Equals(Name, ESearchCase::IgnoreCase);
} }
bool MCPUtils::Identifies(const FString &Name, const UEdGraphPin *Pin) // ============================================================
{ // Formatting other things
return FormatName(Pin).Equals(Name, ESearchCase::IgnoreCase); // ============================================================
}
bool MCPUtils::Identifies(const FString &Name, const FMemberReference &Ref)
{
return FormatName(Ref).Equals(Name, ESearchCase::IgnoreCase);
}
FString MCPUtils::FormatPinType(const FEdGraphPinType& PinType) FString MCPUtils::FormatPinType(const FEdGraphPinType& PinType)
{ {
@@ -386,6 +281,14 @@ FString MCPUtils::FormatPinType(UEdGraphPin* Pin)
return FormatPinType(Pin->PinType); return FormatPinType(Pin->PinType);
} }
FString MCPUtils::FormatNodeTitle(const UEdGraphNode *Node)
{
FString Title = Node->GetNodeTitle(ENodeTitleType::FullTitle).ToString();
int32 NewlineIdx;
if (Title.FindChar(TEXT('\n'), NewlineIdx))
Title.LeftInline(NewlineIdx);
return Title;
}
// ============================================================ // ============================================================
// JSON helpers // JSON helpers
@@ -1210,6 +1113,29 @@ UMaterial* MCPUtils::ReplaceMaterialWithTransientCopy(UMaterial* Material)
return Material; return Material;
} }
// ============================================================
// PreEdit / PostEdit
// ============================================================
void MCPUtils::PreEdit(const TArray<UObject*>& Objects)
{
for (UObject* Obj : Objects)
Obj->PreEditChange(nullptr);
}
void MCPUtils::PostEdit(const TArray<UObject*>& Objects)
{
for (int32 i = Objects.Num() - 1; i >= 0; --i)
{
UObject* Obj = Objects[i];
Obj->PostEditChange();
Obj->MarkPackageDirty();
if (UBlueprint* BP = Cast<UBlueprint>(Obj))
FBlueprintEditorUtils::MarkBlueprintAsModified(BP);
}
}
bool MCPUtils::SaveMaterialPackage(UMaterial* Material) bool MCPUtils::SaveMaterialPackage(UMaterial* Material)
{ {
if (!Material) return false; if (!Material) return false;
@@ -1761,10 +1687,10 @@ FString MCPUtils::FormatPropertyType(FProperty* Prop)
} }
// ============================================================ // ============================================================
// GetEditableTemplate // GetTemplate
// ============================================================ // ============================================================
UObject* MCPUtils::GetEditableTemplate(UObject* Obj, MCPErrorCallback Error) UObject* MCPUtils::GetTemplate(UObject* Obj, MCPErrorCallback Error)
{ {
if (!Obj) if (!Obj)
{ {
@@ -1783,17 +1709,7 @@ UObject* MCPUtils::GetEditableTemplate(UObject* Obj, MCPErrorCallback Error)
return BP->GeneratedClass->GetDefaultObject(); return BP->GeneratedClass->GetDefaultObject();
} }
// These asset types are safe to edit directly. return Obj;
if (Cast<UMaterial>(Obj)) return Obj;
if (Cast<UMaterialInstance>(Obj)) return Obj;
if (Cast<UStaticMesh>(Obj)) return Obj;
if (Cast<USkeletalMesh>(Obj)) return Obj;
if (Cast<UTexture>(Obj)) return Obj;
if (Cast<UActorComponent>(Obj)) return Obj;
// Unknown type — refuse for safety.
Error.SetError(FString::Printf(TEXT("Object type '%s' is not supported for generic property editing"), *Obj->GetClass()->GetName()));
return nullptr;
} }
// ============================================================ // ============================================================
@@ -1856,18 +1772,20 @@ bool MCPUtils::SetPropertyValueText(UObject* Container, FProperty* Prop, const F
} }
// ============================================================ // ============================================================
// BlueprintVisibleProperties // SearchProperties
// ============================================================ // ============================================================
TArray<FProperty*> MCPUtils::BlueprintVisibleProperties(UObject* Obj, const FString& Query) TArray<FProperty*> MCPUtils::SearchProperties(UObject* Obj, const FString& Query, EPropertyFlags Flags, bool bLocal)
{ {
TArray<FProperty*> Result; TArray<FProperty*> Result;
if (!Obj) return Result; if (!Obj) return Result;
for (TFieldIterator<FProperty> PropIt(Obj->GetClass()); PropIt; ++PropIt) UClass* ObjClass = Obj->GetClass();
for (TFieldIterator<FProperty> PropIt(ObjClass); PropIt; ++PropIt)
{ {
FProperty* Prop = *PropIt; FProperty* Prop = *PropIt;
if (!Prop) continue; if (!Prop) continue;
if (!Prop->HasAnyPropertyFlags(CPF_BlueprintVisible)) continue; if (Flags != 0 && !Prop->HasAnyPropertyFlags(Flags)) continue;
if (bLocal && Prop->GetOwnerStruct() != ObjClass) continue;
if (!Query.IsEmpty() && !FormatName(Prop).Contains(Query, ESearchCase::IgnoreCase)) if (!Query.IsEmpty() && !FormatName(Prop).Contains(Query, ESearchCase::IgnoreCase))
continue; continue;
Result.Add(Prop); Result.Add(Prop);

View File

@@ -59,11 +59,11 @@ private:
FString FormatPinSource(UEdGraphPin* Pin); FString FormatPinSource(UEdGraphPin* Pin);
void Traverse(UEdGraphNode* Node); void Traverse(UEdGraphNode* Node);
void SortNodes(); void SortNodes();
void AssignNodeNames();
void EmitNode(UEdGraphNode* Node); void EmitNode(UEdGraphNode* Node);
void EmitLocalVariables(); void EmitLocalVariables();
void EmitGraph(); void EmitGraph();
void EmitNodeList(); void EmitDetails();
void EmitComments();
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
// //

View File

@@ -11,17 +11,11 @@ class UEdGraphPin;
// followed by zero or more comma-separated walker segments of the form // followed by zero or more comma-separated walker segments of the form
// "key:value". Each segment navigates from the current object to a child. // "key:value". Each segment navigates from the current object to a child.
// //
// Supported walkers: // The list of supported walkers is defined by GetWalkerTable().
// graph:Name - find a named UEdGraph within a UBlueprint
// node:Name - find a named UEdGraphNode within a UEdGraph
// pin:Name - find a named UEdGraphPin on a UEdGraphNode
// component:Name - find a named component in a Blueprint's SCS
// property:Name - follow an object-valued UProperty to its value
// levelblueprint - get the level blueprint from a UWorld
// //
// Example paths: // Example paths:
// /Game/Widgets/WB_Hotkeys,graph:ReadLuaConfiguration,node:Self_Reference_03,pin:Result // /Game/Widgets/WB_Hotkeys,graph:ReadLuaConfiguration,node:Self_Reference_03,pin:Result
// /Game/Tangibles/TAN_Character,component:CharacterMesh0,property:SkeletalMeshAsset // /Game/Tangibles/TAN_Character,component:CharacterMesh0
// //
// Builder-style usage: // Builder-style usage:
// MCPFetcher F(cb); // MCPFetcher F(cb);
@@ -46,13 +40,31 @@ public:
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& Property(const FString& Value); MCPFetcher& LevelBlueprint(const FString& Value);
MCPFetcher& LevelBlueprint(); MCPFetcher& MatExp(const FString& Value);
// C++-only walk step: resolve to the editable template
// (e.g. Blueprint → CDO, everything else → as-is).
MCPFetcher& Template();
// Parse string and walk multiple steps. // Parse string and walk multiple steps.
MCPFetcher& Walk(const FString& Path); MCPFetcher& Walk(const FString& Path);
// Walker table entry.
struct FWalker
{
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; }
const TArray<UObject*>& Visited() const { return Chain; }
void PreEdit() { MCPUtils::PreEdit(Chain); }
void PostEdit() { MCPUtils::PostEdit(Chain); }
template<class T> T *Cast() template<class T> T *Cast()
{ {
if (bError) return nullptr; if (bError) return nullptr;
@@ -63,8 +75,9 @@ public:
} }
private: private:
TArray<UObject*> Chain;
static bool StrEq(const FString& A, const TCHAR* B) { return A.Equals(B, ESearchCase::IgnoreCase); } static bool StrEq(const FString& A, const TCHAR* B) { return A.Equals(B, ESearchCase::IgnoreCase); }
void SetObj(UObject* InObj) { Obj = InObj; ResultPin = nullptr; } void SetObj(UObject* InObj) { if (InObj) Chain.AddUnique(InObj); Obj = InObj; ResultPin = nullptr; }
void SetPin(UEdGraphPin* InPin) { ResultPin = InPin; Obj = nullptr; } void SetPin(UEdGraphPin* InPin) { ResultPin = InPin; Obj = nullptr; }
MCPFetcher& SetError(const FString& Msg); MCPFetcher& SetError(const FString& Msg);
MCPFetcher& TypeMismatch(const TCHAR* Walker, const TCHAR* Expected); MCPFetcher& TypeMismatch(const TCHAR* Walker, const TCHAR* Expected);

View File

@@ -148,32 +148,20 @@ public:
// //
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
static bool Identifies(const FString &Name, const UWorld *World); template<typename T>
static bool Identifies(const FString &Name, const UBlueprint *BP); static bool Identifies(const FString &Name, T&& Obj)
static bool Identifies(const FString &Name, const UActorComponent *C); {
static bool Identifies(const FString &Name, const UEdGraph *Graph); return FormatName(std::forward<T>(Obj)).Equals(Name, ESearchCase::IgnoreCase);
}
// UEdGraphNode also matches by GUID.
static bool Identifies(const FString &Name, const UEdGraphNode* Node); static bool Identifies(const FString &Name, const UEdGraphNode* Node);
static bool Identifies(const FString &Name, const UEdGraphPin *Pin);
static bool Identifies(const FString &Name, const FMemberReference &Ref);
static bool Identifies(const FString &Name, const FBPVariableDescription &Var);
static bool Identifies(const FString &Name, const UStruct *Struct);
static bool Identifies(const FString &Name, const UMaterial *Material);
static bool Identifies(const FString &Name, const UMaterialInstance *MaterialInstance);
static bool Identifies(const FString &Name, const UMaterialFunction *MaterialFunction);
static bool Identifies(const FString &Name, const UMaterialExpression *Expression);
static bool Identifies(const FString &Name, const UStaticMesh *Mesh);
static bool Identifies(const FString &Name, const USkeletalMesh *Mesh);
static bool Identifies(const FString &Name, const UAnimSequence *Anim);
static bool Identifies(const FString &Name, const UBlendSpace *BlendSpace);
static bool Identifies(const FString &Name, const UTexture *Texture);
static bool Identifies(const FString &Name, const UScriptStruct *Struct);
static bool Identifies(const FString &Name, const UEnum *Enum);
static bool Identifies(const FString &Name, const FProperty *Prop);
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
static FString FormatPinType(const FEdGraphPinType& PinType); static FString FormatPinType(const FEdGraphPinType& PinType);
static FString FormatPinType(UEdGraphPin* Pin); static FString FormatPinType(UEdGraphPin* Pin);
static FString FormatNodeTitle(const UEdGraphNode *Node);
// ----- Asset path helpers ----- // ----- Asset path helpers -----
// Splits "/Game/Foo/Bar" into PackagePath="/Game/Foo" and AssetName="Bar". // Splits "/Game/Foo/Bar" into PackagePath="/Game/Foo" and AssetName="Bar".
@@ -282,12 +270,19 @@ public:
static FString ActionFullName(const TSharedPtr<FEdGraphSchemaAction>& Action); static FString ActionFullName(const TSharedPtr<FEdGraphSchemaAction>& Action);
static TArray<TSharedPtr<FEdGraphSchemaAction>> SearchGraphActions(UEdGraph* Graph, const FString& Query, int32 MaxResults = 0, bool ExactMatch = false); static TArray<TSharedPtr<FEdGraphSchemaAction>> SearchGraphActions(UEdGraph* Graph, const FString& Query, int32 MaxResults = 0, bool ExactMatch = false);
// ----- Pre/Post edit -----
// Call before and after modifying objects. Walks the list looking for
// known parent types (UMaterial, UBlueprint, etc.) and issues the
// appropriate notifications.
static void PreEdit(const TArray<UObject*>& Objects);
static void PostEdit(const TArray<UObject*>& Objects);
// ----- Editable template ----- // ----- Editable template -----
// Given an object, returns the appropriate template object for generic // Given an object, returns the appropriate template object for generic
// property editing, or nullptr if the type isn't whitelisted. // property editing, or nullptr if the type isn't whitelisted.
// UBlueprint → CDO; UMaterial, UActorComponent, etc. → as-is. // UBlueprint → CDO; UMaterial, UActorComponent, etc. → as-is.
static UObject* GetEditableTemplate(UObject* Obj, MCPErrorCallback Error); static UObject* GetTemplate(UObject* Obj, MCPErrorCallback Error);
static TArray<FProperty*> BlueprintVisibleProperties(UObject* Obj, const FString& Query = FString()); static TArray<FProperty*> SearchProperties(UObject* Obj, const FString& Query, EPropertyFlags Flags, bool bLocal);
static FProperty* FindPropertyByName(UObject* Obj, const FString& Name, MCPErrorCallback Error = nullptr); static FProperty* FindPropertyByName(UObject* Obj, const FString& Name, MCPErrorCallback Error = nullptr);
static FString GetPropertyValueText(UObject* Container, FProperty* Prop); static FString GetPropertyValueText(UObject* Container, FProperty* Prop);

View File

@@ -1720,7 +1720,6 @@ p_thread(Info *info) { /* ... thread */
/* Write general information. */ /* Write general information. */
WRITE_VALUE(thread->status, uint8_t); WRITE_VALUE(thread->status, uint8_t);
WRITE_VALUE(thread->nextid, uint64_t);
WRITE_VALUE(eris_savestackidx(thread, WRITE_VALUE(eris_savestackidx(thread,
eris_restorestack(thread, thread->errfunc)), size_t); eris_restorestack(thread, thread->errfunc)), size_t);
/* These are only used while a thread is being executed or can be deduced: /* These are only used while a thread is being executed or can be deduced:
@@ -1887,7 +1886,6 @@ u_thread(Info *info) { /* ... */
/* Read general information. */ /* Read general information. */
thread->status = READ_VALUE(uint8_t); thread->status = READ_VALUE(uint8_t);
thread->nextid = READ_VALUE(uint64_t);
thread->errfunc = eris_savestack(thread, thread->errfunc = eris_savestack(thread,
eris_restorestackidx(thread, READ_VALUE(size_t))); eris_restorestackidx(thread, READ_VALUE(size_t)));
if (thread->errfunc) { if (thread->errfunc) {

Some files were not shown because too many files have changed in this diff Show More