type parser.

This commit is contained in:
2026-03-15 05:52:11 -04:00
parent 72139e9be5
commit 9a2c4452d4
15 changed files with 38 additions and 251 deletions

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "StructUtils/UserDefinedStruct.h" #include "StructUtils/UserDefinedStruct.h"
#include "UserDefinedStructure/UserDefinedStructEditorData.h" #include "UserDefinedStructure/UserDefinedStructEditorData.h"
@@ -42,7 +43,7 @@ public:
// Resolve type // Resolve type
FEdGraphPinType PinType; FEdGraphPinType PinType;
if (!MCPUtils::ResolveTypeFromString(Type, PinType, Result)) if (!UMCPTypes::TextToType(Type, PinType, Result))
return; return;
// Snapshot existing GUIDs so we can find the newly added one // Snapshot existing GUIDs so we can find the newly added one

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPTypes.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
@@ -128,7 +129,7 @@ public:
if (Entry.Name.IsEmpty() || Entry.Type.IsEmpty()) continue; if (Entry.Name.IsEmpty() || Entry.Type.IsEmpty()) continue;
FEdGraphPinType PinType; FEdGraphPinType PinType;
if (!MCPUtils::ResolveTypeFromString(Entry.Type, PinType)) if (!UMCPTypes::TextToType(Entry.Type, PinType))
return; return;
EntryNode->CreateUserDefinedPin(FName(*Entry.Name), PinType, EGPD_Output); EntryNode->CreateUserDefinedPin(FName(*Entry.Name), PinType, EGPD_Output);

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
@@ -50,7 +51,7 @@ public:
// Resolve param type // Resolve param type
FEdGraphPinType PinType; FEdGraphPinType PinType;
if (!MCPUtils::ResolveTypeFromString(ParamType, PinType)) if (!UMCPTypes::TextToType(ParamType, PinType))
return; return;
// Find the entry node using 3 strategies // Find the entry node using 3 strategies

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
@@ -62,7 +63,7 @@ public:
// Resolve the type // Resolve the type
FEdGraphPinType PinType; FEdGraphPinType PinType;
if (!MCPUtils::ResolveTypeFromString(VariableType, PinType)) if (!UMCPTypes::TextToType(VariableType, PinType))
return; return;
if (IsArray) if (IsArray)

View File

@@ -54,7 +54,7 @@ public:
// Resolve the new type using the shared resolver (supports primitives, structs, enums, and object references) // Resolve the new type using the shared resolver (supports primitives, structs, enums, and object references)
FEdGraphPinType NewPinType; FEdGraphPinType NewPinType;
if (!MCPUtils::ResolveTypeFromString(NewType, NewPinType)) if (!UMCPTypes::TextToType(NewType, NewPinType))
return; return;
// Find the entry node: K2Node_FunctionEntry in a function graph, // Find the entry node: K2Node_FunctionEntry in a function graph,

View File

@@ -82,7 +82,7 @@ public:
ResolveInput = TypeCategory + TEXT(":") + NewType; ResolveInput = TypeCategory + TEXT(":") + NewType;
} }
if (!MCPUtils::ResolveTypeFromString(ResolveInput, NewPinType)) if (!UMCPTypes::TextToType(ResolveInput, NewPinType))
return; return;
// List affected nodes (get/set nodes for this variable) // List affected nodes (get/set nodes for this variable)

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "Class_ShowProperties.generated.h" #include "Class_ShowProperties.generated.h"
@@ -62,7 +63,7 @@ public:
if (Prop->HasAnyPropertyFlags(CPF_RepNotify)) Flags.Append(TEXT(" RepNotify")); if (Prop->HasAnyPropertyFlags(CPF_RepNotify)) Flags.Append(TEXT(" RepNotify"));
UClass* OwnerClass = Prop->GetOwnerClass(); UClass* OwnerClass = Prop->GetOwnerClass();
UMCPServer::Printf(TEXT(" %s %s"), *MCPUtils::FormatPropertyType(Prop), *PropName); UMCPServer::Printf(TEXT(" %s %s"), *UMCPTypes::TypeToText(Prop), *PropName);
if (OwnerClass && OwnerClass != FoundClass) if (OwnerClass && OwnerClass != FoundClass)
UMCPServer::Printf(TEXT(" [%s]"), *MCPUtils::FormatName(OwnerClass)); UMCPServer::Printf(TEXT(" [%s]"), *MCPUtils::FormatName(OwnerClass));
if (Flags.Len() > 0) if (Flags.Len() > 0)

View File

@@ -5,6 +5,7 @@
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPProperty.h" #include "MCPProperty.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "Property_Dump.generated.h" #include "Property_Dump.generated.h"
@@ -86,7 +87,7 @@ public:
bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst); bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst);
UMCPServer::Printf(TEXT(" %s %s %s = %s\n"), UMCPServer::Printf(TEXT(" %s %s %s = %s\n"),
bEditable ? TEXT("editable") : TEXT("readonly"), bEditable ? TEXT("editable") : TEXT("readonly"),
*MCPUtils::FormatPropertyType(P.Prop), *UMCPTypes::TypeToText(P.Prop),
*PropName, *PropName,
*ValueStr); *ValueStr);
} }

View File

@@ -4,6 +4,7 @@
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPFetcher.h" #include "MCPFetcher.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "ShowCommands.generated.h" #include "ShowCommands.generated.h"
@@ -57,7 +58,7 @@ public:
if (!bFirst) UMCPServer::Print(TEXT(",")); if (!bFirst) UMCPServer::Print(TEXT(","));
bFirst = false; bFirst = false;
if (PropIt->HasMetaData(TEXT("Optional"))) UMCPServer::Print(TEXT("?")); if (PropIt->HasMetaData(TEXT("Optional"))) UMCPServer::Print(TEXT("?"));
UMCPServer::Print(MCPUtils::FormatPropertyType(*PropIt)); UMCPServer::Print(UMCPTypes::TypeToText(*PropIt));
UMCPServer::Print(TEXT(" ")); UMCPServer::Print(TEXT(" "));
UMCPServer::Print(MCPUtils::PropertyNameToJsonKey(PropIt->GetName())); UMCPServer::Print(MCPUtils::PropertyNameToJsonKey(PropIt->GetName()));
} }

View File

@@ -3,6 +3,7 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "MCPTypes.h"
#include "MCPUtils.h" #include "MCPUtils.h"
#include "StructUtils/UserDefinedStruct.h" #include "StructUtils/UserDefinedStruct.h"
#include "Kismet2/BlueprintEditorUtils.h" #include "Kismet2/BlueprintEditorUtils.h"
@@ -63,7 +64,7 @@ public:
if (Entry.Name.IsEmpty() || Entry.Type.IsEmpty()) continue; if (Entry.Name.IsEmpty() || Entry.Type.IsEmpty()) continue;
FEdGraphPinType PinType; FEdGraphPinType PinType;
if (!MCPUtils::ResolveTypeFromString(Entry.Type, PinType)) if (!UMCPTypes::TextToType(Entry.Type, PinType))
continue; continue;
// Snapshot existing GUIDs so we can find the newly added one. // Snapshot existing GUIDs so we can find the newly added one.

View File

@@ -258,7 +258,7 @@ void FlxBlueprintExporter::EmitMaterialProperty(UMaterialExpression* Expression,
bool bEditable = !Prop->HasAnyPropertyFlags(CPF_EditConst); bool bEditable = !Prop->HasAnyPropertyFlags(CPF_EditConst);
Out.Appendf(TEXT(" %s %s %s = %s\n"), Out.Appendf(TEXT(" %s %s %s = %s\n"),
bEditable ? TEXT("mxeditable") : TEXT("mxreadonly"), bEditable ? TEXT("mxeditable") : TEXT("mxreadonly"),
*MCPUtils::FormatPropertyType(Prop), *UMCPTypes::TypeToText(Prop),
*MCPUtils::FormatName(Prop), *MCPUtils::FormatName(Prop),
*ValueStr); *ValueStr);
} }

View File

@@ -142,6 +142,18 @@ FString UMCPTypes::TypeToText(const FEdGraphPinType& PinType)
return Inner; return Inner;
} }
FString UMCPTypes::TypeToText(const FProperty *Property)
{
FEdGraphPinType PinType;
if (!GetDefault<UEdGraphSchema_K2>()->ConvertPropertyToPinType(Property, PinType))
{
return TEXT("void");
}
else
{
return TypeToText(PinType);
}
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Subsystem lifecycle // Subsystem lifecycle

View File

@@ -1,4 +1,5 @@
#include "MCPUtils.h" #include "MCPUtils.h"
#include "MCPTypes.h"
#include "MCPServer.h" #include "MCPServer.h"
#include "MCPHandler.h" #include "MCPHandler.h"
#include "Dom/JsonValue.h" #include "Dom/JsonValue.h"
@@ -477,12 +478,10 @@ bool MCPUtils::SaveBlueprintPackage(UBlueprint* BP)
*BP->GetName(), bCompiled ? TEXT("yes") : TEXT("no"), (int32)SaveResult); *BP->GetName(), bCompiled ? TEXT("yes") : TEXT("no"), (int32)SaveResult);
return bSuccess; return bSuccess;
}
}// ============================================================
// FindClassByName
// ============================================================ // ============================================================
// FindClassByName / ResolveTypeFromString
// ============================================================
UClass* MCPUtils::FindClassByName(const FString& ClassName) UClass* MCPUtils::FindClassByName(const FString& ClassName)
{ {
@@ -509,216 +508,6 @@ UClass* MCPUtils::FindClassByName(const FString& ClassName)
return nullptr; return nullptr;
} }
bool MCPUtils::ResolveTypeFromString(
const FString& TypeName, FEdGraphPinType& OutPinType)
{
FString TypeLower = TypeName.ToLower();
if (TypeLower == TEXT("bool") || TypeLower == TEXT("boolean"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Boolean;
}
else if (TypeLower == TEXT("int") || TypeLower == TEXT("int32") || TypeLower == TEXT("integer"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Int;
}
else if (TypeLower == TEXT("int64"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Int64;
}
else if (TypeLower == TEXT("float") || TypeLower == TEXT("double") || TypeLower == TEXT("real"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Real;
OutPinType.PinSubCategory = TEXT("double");
}
else if (TypeLower == TEXT("string"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_String;
}
else if (TypeLower == TEXT("name"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Name;
}
else if (TypeLower == TEXT("text"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Text;
}
else if (TypeLower == TEXT("byte"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Byte;
}
else if (TypeLower == TEXT("vector") || TypeLower == TEXT("fvector"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
OutPinType.PinSubCategoryObject = TBaseStructure<FVector>::Get();
}
else if (TypeLower == TEXT("rotator") || TypeLower == TEXT("frotator"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
OutPinType.PinSubCategoryObject = TBaseStructure<FRotator>::Get();
}
else if (TypeLower == TEXT("transform") || TypeLower == TEXT("ftransform"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
OutPinType.PinSubCategoryObject = TBaseStructure<FTransform>::Get();
}
else if (TypeLower == TEXT("linearcolor") || TypeLower == TEXT("flinearcolor"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
OutPinType.PinSubCategoryObject = TBaseStructure<FLinearColor>::Get();
}
else if (TypeLower == TEXT("vector2d") || TypeLower == TEXT("fvector2d"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
OutPinType.PinSubCategoryObject = TBaseStructure<FVector2D>::Get();
}
else if (TypeLower == TEXT("object"))
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Object;
OutPinType.PinSubCategoryObject = UObject::StaticClass();
}
else if (TypeName.StartsWith(TEXT("object:"), ESearchCase::IgnoreCase))
{
FString ClassName = TypeName.Mid(7); // after "object:"
UClass* FoundClass = FindClassByName(ClassName);
if (!FoundClass)
{
UMCPServer::Printf(TEXT("ERROR: Class '%s' not found for object reference type\n"), *ClassName);
return false;
}
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Object;
OutPinType.PinSubCategoryObject = FoundClass;
}
else if (TypeName.StartsWith(TEXT("softobject:"), ESearchCase::IgnoreCase))
{
FString ClassName = TypeName.Mid(11); // after "softobject:"
UClass* FoundClass = FindClassByName(ClassName);
if (!FoundClass)
{
UMCPServer::Printf(TEXT("ERROR: Class '%s' not found for soft object reference type\n"), *ClassName);
return false;
}
OutPinType.PinCategory = UEdGraphSchema_K2::PC_SoftObject;
OutPinType.PinSubCategoryObject = FoundClass;
}
else if (TypeName.StartsWith(TEXT("class:"), ESearchCase::IgnoreCase))
{
FString ClassName = TypeName.Mid(6); // after "class:"
UClass* FoundClass = FindClassByName(ClassName);
if (!FoundClass)
{
UMCPServer::Printf(TEXT("ERROR: Class '%s' not found for class reference type (TSubclassOf)\n"), *ClassName);
return false;
}
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Class;
OutPinType.PinSubCategoryObject = FoundClass;
}
else if (TypeName.StartsWith(TEXT("softclass:"), ESearchCase::IgnoreCase))
{
FString ClassName = TypeName.Mid(10); // after "softclass:"
UClass* FoundClass = FindClassByName(ClassName);
if (!FoundClass)
{
UMCPServer::Printf(TEXT("ERROR: Class '%s' not found for soft class reference type\n"), *ClassName);
return false;
}
OutPinType.PinCategory = UEdGraphSchema_K2::PC_SoftClass;
OutPinType.PinSubCategoryObject = FoundClass;
}
else if (TypeName.StartsWith(TEXT("interface:"), ESearchCase::IgnoreCase))
{
FString ClassName = TypeName.Mid(10); // after "interface:"
UClass* FoundClass = FindClassByName(ClassName);
if (!FoundClass)
{
UMCPServer::Printf(TEXT("ERROR: Class '%s' not found for interface reference type\n"), *ClassName);
return false;
}
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Interface;
OutPinType.PinSubCategoryObject = FoundClass;
}
else
{
// Try as a struct (F-prefix or raw name)
FString InternalName = TypeName;
bool bTriedAsStruct = false;
if (TypeName.StartsWith(TEXT("F")) || TypeName.StartsWith(TEXT("S_")) || (!TypeName.StartsWith(TEXT("E"))))
{
if (TypeName.StartsWith(TEXT("F")))
{
InternalName = TypeName.Mid(1);
}
UScriptStruct* FoundStruct = FindFirstObject<UScriptStruct>(*InternalName);
if (!FoundStruct)
{
for (TObjectIterator<UScriptStruct> It; It; ++It)
{
if (It->GetName() == InternalName || It->GetName() == TypeName)
{
FoundStruct = *It;
break;
}
}
}
if (FoundStruct)
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Struct;
OutPinType.PinSubCategoryObject = FoundStruct;
bTriedAsStruct = true;
}
}
if (!bTriedAsStruct)
{
// Try as an enum (E-prefix or raw name)
FString EnumInternalName = TypeName;
if (TypeName.StartsWith(TEXT("E")))
{
EnumInternalName = TypeName.Mid(1);
}
UEnum* FoundEnum = FindFirstObject<UEnum>(*EnumInternalName);
if (!FoundEnum)
{
for (TObjectIterator<UEnum> It; It; ++It)
{
if (It->GetName() == EnumInternalName || It->GetName() == TypeName)
{
FoundEnum = *It;
break;
}
}
}
if (FoundEnum)
{
if (FoundEnum->GetCppForm() == UEnum::ECppForm::EnumClass)
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Enum;
}
else
{
OutPinType.PinCategory = UEdGraphSchema_K2::PC_Byte;
}
OutPinType.PinSubCategoryObject = FoundEnum;
}
else
{
UMCPServer::Printf(
TEXT("ERROR: Unknown type '%s'. Use: bool, int, float, string, name, text, byte, vector, rotator, transform, object, a struct/enum name (e.g. FVector, EMyEnum), or colon syntax for references (object:Actor, softobject:Actor, class:Actor, softclass:Actor, interface:MyInterface)\n"),
*TypeName);
return false;
}
}
}
return true;
}
// ============================================================ // ============================================================
// Material helpers // Material helpers
// ============================================================ // ============================================================
@@ -1262,25 +1051,6 @@ FString MCPUtils::GetHandlerGroup(UClass* HandlerClass)
return Name; return Name;
} }
// ============================================================
// FormatPropertyType — human-readable type name for a UPROPERTY
// ============================================================
FString MCPUtils::FormatPropertyType(FProperty* Prop)
{
if (CastField<FStrProperty>(Prop)) return TEXT("string");
if (CastField<FIntProperty>(Prop)) return TEXT("integer");
if (CastField<FFloatProperty>(Prop) || CastField<FDoubleProperty>(Prop)) return TEXT("number");
if (CastField<FBoolProperty>(Prop)) return TEXT("boolean");
if (FStructProperty* SP = CastField<FStructProperty>(Prop))
{
FString StructName = SP->Struct->GetName();
StructName.ReplaceInline(TEXT("MCP"), TEXT(""));
return StructName;
}
return TEXT("string");
}
// ============================================================ // ============================================================
// GetTemplate // GetTemplate
// ============================================================ // ============================================================
@@ -1412,7 +1182,7 @@ void MCPUtils::FormatCommandHelp(UClass* HandlerClass)
{ {
FProperty* Prop = *PropIt; FProperty* Prop = *PropIt;
FString Name = PropertyNameToJsonKey(Prop->GetName()); FString Name = PropertyNameToJsonKey(Prop->GetName());
FString Type = FormatPropertyType(Prop); FString Type = UMCPTypes::TypeToText(Prop);
bool bOptional = Prop->HasMetaData(TEXT("Optional")); bool bOptional = Prop->HasMetaData(TEXT("Optional"));
const FString& Desc = Prop->GetMetaData(TEXT("Description")); const FString& Desc = Prop->GetMetaData(TEXT("Description"));

View File

@@ -20,6 +20,7 @@ public:
// Convert a pin type to a type string. Returns empty string on failure. // Convert a pin type to a type string. Returns empty string on failure.
static FString TypeToText(const FEdGraphPinType& PinType); static FString TypeToText(const FEdGraphPinType& PinType);
static FString TypeToText(const FProperty *Property);
// Try to parse a type. If there's a problem, returns an error // Try to parse a type. If there's a problem, returns an error
// message. If all goes well, returns empty string. // message. If all goes well, returns empty string.

View File

@@ -133,11 +133,7 @@ public:
return Result; return Result;
} }
static bool SaveBlueprintPackage(UBlueprint* BP); static bool SaveBlueprintPackage(UBlueprint* BP);
// ----- Type resolution -----
static UClass* FindClassByName(const FString& ClassName); static UClass* FindClassByName(const FString& ClassName);
static bool ResolveTypeFromString(const FString& TypeName, FEdGraphPinType& OutPinType);
static FString FormatPropertyType(FProperty* Prop);
// ----- Material helpers ----- // ----- Material helpers -----
static void EnsureMaterialGraph(UMaterial* Material); static void EnsureMaterialGraph(UMaterial* Material);