diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintComponent_Add.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintComponent_Add.h index 499c5c4e..9dce477f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintComponent_Add.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintComponent_Add.h @@ -79,7 +79,7 @@ public: } // Create the SCS node - USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*Component)); + USCS_Node* NewNode = SCS->CreateNode(ComponentClassObj, FName(*WingUtils::UnsanitizeName(Component))); if (!NewNode) { UWingServer::Printf(TEXT("ERROR: Failed to create SCS node for component '%s' with class '%s'\n"), diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h index d266a289..cb91332c 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/BlueprintVariable_Create.h @@ -46,7 +46,7 @@ public: if (!BP) return; // Check for duplicate variable name - FName VarFName(*Name); + FName VarFName(*WingUtils::UnsanitizeName(Name)); if (FBlueprintEditorUtils::FindNewVariableIndex(BP, VarFName) != INDEX_NONE) { UWingServer::Printf(TEXT("ERROR: Variable '%s' already exists in %s\n"), *Name, *WingUtils::FormatName(BP)); diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp index 50cbc0df..267e25c6 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp @@ -115,7 +115,20 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath) { if (bError) return *this; - SetObj(LoadObject(nullptr, *PackagePath)); + // Try to find the object in memory first (silent), then load if needed. + // LoadObject logs its own errors when the package doesn't exist, so + // we check DoesPackageExist first to avoid redundant log spam. + SetObj(FindObject(nullptr, *PackagePath)); + if (!Obj) + { + FString PackageName = FPackageName::ObjectPathToPackageName(PackagePath); + if (!FPackageName::DoesPackageExist(PackageName)) + { + UWingServer::Printf(TEXT("ERROR: Asset '%s' does not exist.\n"), *PackagePath); + return SetError(); + } + SetObj(LoadObject(nullptr, *PackagePath)); + } if (!Obj) { UWingServer::Printf(TEXT("ERROR: Could not load asset '%s'\n"), *PackagePath); diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp index 89d50170..bf1546fa 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp @@ -3,6 +3,7 @@ #include "WingServer.h" #include "WingTypes.h" #include "Engine/Blueprint.h" +#include "Engine/SCS_Node.h" #include "MaterialGraph/MaterialGraphNode.h" #include "EdGraph/EdGraphPin.h" #include "UObject/EnumProperty.h" @@ -138,6 +139,19 @@ TArray FWingProperty::GetAll(UObject* Obj, EPropertyFlags Flags) Obj = BP->GeneratedClass->GetDefaultObject(); } + // SCS nodes don't have useful editable properties. + // Redirect to the component template instead. + // + if (USCS_Node* Node = ::Cast(Obj)) + { + if (!Node->ComponentTemplate) + { + UWingServer::Printf(TEXT("ERROR: SCS node '%s' has no component template\n"), *Obj->GetName()); + return {}; + } + Obj = Node->ComponentTemplate; + } + TArray Result; Collect(Obj->GetClass(), Obj, Result, Flags); diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h index d073d836..aa267f9d 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingUtils.h @@ -166,15 +166,15 @@ public: static FString SanitizeName(FName Name); //////////////////////////////////////////////////////// - // Our name sanitization routine, above, will turn - // names with spaces into names like "Post·Initiate·Action" - // containing middle dots instead. There is a risk that the - // LLM will see these dotted names and think it is supposed to - // do that. So, we have an 'Unsanitize' routine to convert - // the middle dots back into spaces. Of course, next time the - // name is output, it will be sanitized again, so the LLM will - // always see the version with dots. This creates consistency - // for both the LLM and the human user (who is expecting whitespace). + // Our name sanitization routine, above, will turn names + // with spaces into names like "Post·Initiate·Action" + // containing middle dots instead. When the LLM creates + // new nodes, graphs, variables, or the like, it might + // suggest a name containing middle dots. In places + // like that, where the LLM is naming something new, we + // run this Unsanitize routine first. This is *not* + // used for lookups: Lookups are done by comparing + // sanitized names. //////////////////////////////////////////////////////// static FString UnsanitizeName(const FString& Name);