More refinement of Wing server
This commit is contained in:
@@ -43,7 +43,7 @@ public:
|
||||
FString OldParentName = BP->ParentClass ? WingUtils::FormatName(BP->ParentClass) : TEXT("None");
|
||||
|
||||
// Find the new parent class by short type name
|
||||
UClass* NewParentClassObj = UWingTypes::TextToOneObjectType(NewParentClass);
|
||||
UClass* NewParentClassObj = UWingTypes::TextToOneObjectType(Parent);
|
||||
if (!NewParentClassObj) return;
|
||||
|
||||
// Perform reparent
|
||||
@@ -53,7 +53,5 @@ public:
|
||||
|
||||
UWingServer::Printf(TEXT("Reparented %s: %s -> %s\n"),
|
||||
*WingUtils::FormatName(BP), *OldParentName, *WingUtils::FormatName(NewParentClassObj));
|
||||
if (!bSaved)
|
||||
UWingServer::Print(TEXT("Warning: save failed\n"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "WingHandler.h"
|
||||
#include "WingUtils.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/AssetData.h"
|
||||
#include "AssetRegistry/IAssetRegistry.h"
|
||||
#include "Asset_ContentBrowse.generated.h"
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "WingUtils.h"
|
||||
#include "WingTypes.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/AssetData.h"
|
||||
#include "AssetRegistry/IAssetRegistry.h"
|
||||
#include "Asset_Search.generated.h"
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
continue;
|
||||
|
||||
// Find the action by exact full name
|
||||
TArray<TSharedPtr<FEdGraphSchemaAction>> Matches = WingUtils::SearchGraphActions(TargetGraph, Entry.ActionName, 0, /*ExactMatch=*/true);
|
||||
TArray<TSharedPtr<FEdGraphSchemaAction>> Matches = WingUtils::SearchGraphActions(TargetGraph, Entry.ActionName, 2, /*ExactMatch=*/true);
|
||||
if (Matches.Num() == 0)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: No action found matching '%s'. Use GraphNodeSearchTypes to find available actions.\n"),
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
{
|
||||
if (Verbose)
|
||||
{
|
||||
WingUtils::FormatCommandHelp(Class);
|
||||
WingUtils::PrintHandlerHelp(Class);
|
||||
return;
|
||||
}
|
||||
UWingServer::Print(WingUtils::GetHandlerName(Class));
|
||||
|
||||
@@ -8,20 +8,14 @@
|
||||
|
||||
FWingBlueprintVar::FWingBlueprintVar(UBlueprint* BP, const FString& VarName)
|
||||
{
|
||||
FName VarFName(*VarName);
|
||||
int32 VarIndex = FBlueprintEditorUtils::FindNewVariableIndex(BP, VarFName);
|
||||
if (VarIndex == INDEX_NONE)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Variable '%s' not found in %s\n"), *VarName, *WingUtils::FormatName(BP));
|
||||
return;
|
||||
}
|
||||
Desc = &BP->NewVariables[VarIndex];
|
||||
Desc = WingUtils::FindExactlyOneNamed(VarName, BP->NewVariables);
|
||||
if (!Desc) return;
|
||||
|
||||
// Try to find the default value property on the CDO.
|
||||
if (BP->GeneratedClass)
|
||||
{
|
||||
UObject* CDO = BP->GeneratedClass->GetDefaultObject();
|
||||
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(VarFName);
|
||||
FProperty* Prop = BP->GeneratedClass->FindPropertyByName(Desc->VarName);
|
||||
if (CDO && Prop)
|
||||
DefaultValueProp = FWingProperty(Prop, CDO);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "WingGraphExport.h"
|
||||
#include "WingProperty.h"
|
||||
#include "WingTypes.h"
|
||||
#include "WingUtils.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
@@ -263,19 +264,19 @@ void WingGraphExport::EmitNode(UEdGraphNode* Node)
|
||||
}
|
||||
}
|
||||
|
||||
void WingGraphExport::EmitMaterialProperty(UMaterialExpression* Expression, FProperty* Prop, FStringBuilderBase& Out)
|
||||
void WingGraphExport::EmitMaterialProperty(const FWingProperty& WP, FStringBuilderBase& Out)
|
||||
{
|
||||
FString ValueStr = WingUtils::GetPropertyValueText(Expression, Prop);
|
||||
FString ValueStr = WP.GetText();
|
||||
ValueStr.ReplaceInline(TEXT("\r\n"), TEXT(" "));
|
||||
ValueStr.ReplaceInline(TEXT("\n"), TEXT(" "));
|
||||
if (ValueStr.Len() > 80)
|
||||
ValueStr = ValueStr.Left(80) + TEXT("...");
|
||||
|
||||
bool bEditable = !Prop->HasAnyPropertyFlags(CPF_EditConst);
|
||||
bool bEditable = !WP->HasAnyPropertyFlags(CPF_EditConst);
|
||||
Out.Appendf(TEXT(" %s %s %s = %s\n"),
|
||||
bEditable ? TEXT("mxeditable") : TEXT("mxreadonly"),
|
||||
*UWingTypes::TypeToText(Prop),
|
||||
*WingUtils::FormatName(Prop),
|
||||
*UWingTypes::TypeToText(WP.Prop),
|
||||
*WingUtils::FormatName(WP.Prop),
|
||||
*ValueStr);
|
||||
}
|
||||
|
||||
@@ -286,13 +287,13 @@ void WingGraphExport::EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderB
|
||||
|
||||
UMaterialExpression* Expression = MatNode->MaterialExpression;
|
||||
FString PrimaryCategory = Expression->GetClass()->GetName();
|
||||
TArray<FProperty*> Props = WingUtils::SearchProperties(Expression, FString(), CPF_Edit, false);
|
||||
TArray<FWingProperty> Props = FWingProperty::GetAll(Expression, CPF_Edit);
|
||||
|
||||
for (FProperty* Prop : Props)
|
||||
for (const FWingProperty& WP : Props)
|
||||
{
|
||||
FString Category = Prop->HasMetaData(TEXT("Category")) ? Prop->GetMetaData(TEXT("Category")) : FString();
|
||||
FString Category = WP->HasMetaData(TEXT("Category")) ? WP->GetMetaData(TEXT("Category")) : FString();
|
||||
if ((Category == PrimaryCategory) == bPrimary)
|
||||
EmitMaterialProperty(Expression, Prop, Out);
|
||||
EmitMaterialProperty(WP, Out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Misc/OutputDeviceRedirector.h"
|
||||
|
||||
class FLogCaptureOutputDevice : public FOutputDevice
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "WingNotifier.h"
|
||||
#include "Editor.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "EdGraph/EdGraph.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
|
||||
@@ -319,7 +319,7 @@ void UWingServer::TryCallHandler(const FString &Line)
|
||||
if (!WingJson::PopulateFromJson(HandlerObj->GetClass(), HandlerObj.Get(), &*Request))
|
||||
{
|
||||
UWingServer::Printf(TEXT("\nUsage:\n\n"));
|
||||
WingUtils::FormatCommandHelp(*HandlerClass);
|
||||
WingUtils::PrintHandlerHelp(*HandlerClass);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -508,11 +508,7 @@ TArray<TSharedPtr<FEdGraphSchemaAction>> WingUtils::SearchGraphActions(UEdGraph*
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PopulateFromJson — fill a USTRUCT from a JSON object
|
||||
// ============================================================
|
||||
|
||||
// ============================================================
|
||||
// CollectHandlerClasses — find all concrete IWingHandler classes
|
||||
// Support for locating UE Wingman Handlers
|
||||
// ============================================================
|
||||
|
||||
TArray<UClass*> WingUtils::CollectHandlerClasses()
|
||||
@@ -529,26 +525,16 @@ TArray<UClass*> WingUtils::CollectHandlerClasses()
|
||||
return Result;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GetHandlerName — derive tool name from handler class name
|
||||
// ============================================================
|
||||
|
||||
FString WingUtils::GetHandlerName(UClass* HandlerClass)
|
||||
{
|
||||
FString Name = HandlerClass->GetName();
|
||||
// Strip "Wing_" prefix
|
||||
Name.RemoveFromStart(TEXT("Wing_"));
|
||||
return Name;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GetHandlerGroup — derive group name from handler class name
|
||||
// ============================================================
|
||||
|
||||
FString WingUtils::GetHandlerGroup(UClass* HandlerClass)
|
||||
{
|
||||
FString Name = HandlerClass->GetName();
|
||||
// Strip "Wing_" prefix
|
||||
Name.RemoveFromStart(TEXT("Wing_"));
|
||||
// Everything before the underscore is the group
|
||||
int32 UnderscoreIdx;
|
||||
@@ -558,108 +544,10 @@ FString WingUtils::GetHandlerGroup(UClass* HandlerClass)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GetTemplate
|
||||
// PrintHandlerHelp — verbose description of one handler command
|
||||
// ============================================================
|
||||
|
||||
// ============================================================
|
||||
// FindPropertyByName
|
||||
// ============================================================
|
||||
|
||||
FProperty* WingUtils::FindPropertyByName(UObject* Obj, const FString& Name)
|
||||
{
|
||||
if (!Obj)
|
||||
{
|
||||
UWingServer::Print(TEXT("ERROR: Object is null\n"));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FProperty* Found = nullptr;
|
||||
for (TFieldIterator<FProperty> PropIt(Obj->GetClass()); PropIt; ++PropIt)
|
||||
{
|
||||
if (!Identifies(Name, *PropIt)) continue;
|
||||
if (Found)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Ambiguous property '%s' on %s\n"), *Name, *FormatName(Obj->GetClass()));
|
||||
return nullptr;
|
||||
}
|
||||
Found = *PropIt;
|
||||
}
|
||||
|
||||
if (!Found)
|
||||
UWingServer::Printf(TEXT("ERROR: Property '%s' not found on %s\n"), *Name, *FormatName(Obj->GetClass()));
|
||||
|
||||
return Found;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GetPropertyValueText
|
||||
// ============================================================
|
||||
|
||||
FString WingUtils::GetPropertyValueText(UObject* Container, FProperty* Prop)
|
||||
{
|
||||
FString Result;
|
||||
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
|
||||
Prop->ExportTextItem_Direct(Result, ValuePtr, nullptr, Container, PPF_None);
|
||||
return Result;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SetPropertyValueText
|
||||
// ============================================================
|
||||
|
||||
bool WingUtils::SetPropertyValueText(UObject* Container, FProperty* Prop, const FString& Value)
|
||||
{
|
||||
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
|
||||
const TCHAR* ImportResult = Prop->ImportText_Direct(*Value, ValuePtr, Container, PPF_None);
|
||||
if (!ImportResult)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"),
|
||||
*Value, *FormatName(Prop), *Prop->GetCPPType());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WingUtils::SetPropertyValueText(void* Container, FProperty* Prop, const FString& Value, UObject* Owner)
|
||||
{
|
||||
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
|
||||
const TCHAR* ImportResult = Prop->ImportText_Direct(*Value, ValuePtr, Owner, PPF_None);
|
||||
if (!ImportResult)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"),
|
||||
*Value, *FormatName(Prop), *Prop->GetCPPType());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// SearchProperties
|
||||
// ============================================================
|
||||
|
||||
TArray<FProperty*> WingUtils::SearchProperties(UObject* Obj, const FString& Query, EPropertyFlags Flags, bool bLocal)
|
||||
{
|
||||
TArray<FProperty*> Result;
|
||||
if (!Obj) return Result;
|
||||
UClass* ObjClass = Obj->GetClass();
|
||||
for (TFieldIterator<FProperty> PropIt(ObjClass); PropIt; ++PropIt)
|
||||
{
|
||||
FProperty* Prop = *PropIt;
|
||||
if (!Prop) continue;
|
||||
if (Flags != 0 && !Prop->HasAnyPropertyFlags(Flags)) continue;
|
||||
if (bLocal && Prop->GetOwnerStruct() != ObjClass) continue;
|
||||
if (!Query.IsEmpty() && !FormatName(Prop).Contains(Query, ESearchCase::IgnoreCase))
|
||||
continue;
|
||||
Result.Add(Prop);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// FormatCommandHelp — verbose description of one handler command
|
||||
// ============================================================
|
||||
|
||||
void WingUtils::FormatCommandHelp(UClass* HandlerClass)
|
||||
void WingUtils::PrintHandlerHelp(UClass* HandlerClass)
|
||||
{
|
||||
const IWingHandler* Handler = Cast<IWingHandler>(HandlerClass->GetDefaultObject());
|
||||
if (!Handler) return;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
|
||||
class UEdGraphNode;
|
||||
class UK2Node_EditablePinBase;
|
||||
struct FEdGraphPinType;
|
||||
|
||||
struct WingFunctionArgs
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "EdGraph/EdGraphPin.h"
|
||||
|
||||
class UMaterialExpression;
|
||||
struct FWingProperty;
|
||||
|
||||
class WingGraphExport
|
||||
{
|
||||
@@ -63,7 +64,7 @@ private:
|
||||
void Traverse(UEdGraphNode* Node);
|
||||
void SortNodes();
|
||||
void EmitNode(UEdGraphNode* Node);
|
||||
void EmitMaterialProperty(UMaterialExpression* Expression, FProperty* Prop, FStringBuilderBase& Out);
|
||||
void EmitMaterialProperty(const FWingProperty& WP, FStringBuilderBase& Out);
|
||||
void EmitMaterialProperties(UEdGraphNode* Node, FStringBuilderBase& Out, bool bPrimary);
|
||||
void EmitLocalVariables();
|
||||
void EmitGraph();
|
||||
|
||||
@@ -100,6 +100,14 @@ public:
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static TArray<T*> FindAllNamed(const FString &Name, TArray<T> &Array)
|
||||
{
|
||||
TArray<T*> Result;
|
||||
for (T& Elt : Array) if (Identifies(Name, Elt)) Result.Add(&Elt);
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* FindExactlyOneNamed(const FString &Name, const TArray<T*> &Array)
|
||||
{
|
||||
@@ -110,6 +118,16 @@ public:
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T* FindExactlyOneNamed(const FString &Name, TArray<T> &Array)
|
||||
{
|
||||
int Count = 0;
|
||||
T* Result = nullptr;
|
||||
for (T& Elt : Array) if (Identifies(Name, Elt)) { Count++; Result = &Elt; }
|
||||
if (!CheckExactlyOneNamed(Count, T::StaticStruct()->GetName(), Name)) return nullptr;
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool FindExactlyNoneNamed(const FString &Name, const TArray<T*> &Array)
|
||||
{
|
||||
@@ -120,6 +138,16 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static bool FindExactlyNoneNamed(const FString &Name, const TArray<T> &Array)
|
||||
{
|
||||
for (const T& Elt: Array) if (Identifies(Name, Elt))
|
||||
{
|
||||
return CheckExactlyNoneNamed(1, T::StaticStruct()->GetName(), Name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
|
||||
static void SanitizeNameInPlace(FString& Name);
|
||||
@@ -181,13 +209,6 @@ public:
|
||||
static FString ActionFullName(const TSharedPtr<FEdGraphSchemaAction>& Action);
|
||||
static TArray<TSharedPtr<FEdGraphSchemaAction>> SearchGraphActions(UEdGraph* Graph, const FString& Query, int32 MaxResults = 0, bool ExactMatch = false);
|
||||
|
||||
// ----- Editable template -----
|
||||
static TArray<FProperty*> SearchProperties(UObject* Obj, const FString& Query, EPropertyFlags Flags, bool bLocal);
|
||||
static FProperty* FindPropertyByName(UObject* Obj, const FString& Name);
|
||||
static FString GetPropertyValueText(UObject* Container, FProperty* Prop);
|
||||
static bool SetPropertyValueText(UObject* Container, FProperty* Prop, const FString& Value);
|
||||
static bool SetPropertyValueText(void* Container, FProperty* Prop, const FString& Value, UObject* Owner);
|
||||
|
||||
// ----- Text formatting -----
|
||||
static FString WrapText(const FString& Text, int32 ColLimit, const FString& Prefix);
|
||||
|
||||
@@ -195,7 +216,7 @@ public:
|
||||
static TArray<UClass*> CollectHandlerClasses();
|
||||
static FString GetHandlerName(UClass* HandlerClass);
|
||||
static FString GetHandlerGroup(UClass* HandlerClass);
|
||||
static void FormatCommandHelp(UClass* HandlerClass);
|
||||
static void PrintHandlerHelp(UClass* HandlerClass);
|
||||
|
||||
// ----- Common Error Reporting -----
|
||||
static bool CheckExactlyOneNamed(int Count, const FString &Kind, const FString &Name);
|
||||
@@ -203,7 +224,5 @@ public:
|
||||
static bool CheckExactlyNoneNamed(int Count, const FString &Kind, const FString &Name);
|
||||
static bool CheckExactlyNoneNamed(int Count, UClass *Class, const FString &Name);
|
||||
|
||||
private:
|
||||
static void AppendNumericSuffix(FString &Name, int32 N);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@ SOURCE_DIRS = [
|
||||
"luprex/cpp/core",
|
||||
"luprex/cpp/drv",
|
||||
"luprex/cpp/wrap",
|
||||
"Plugins/BlueprintMCP/Source/BlueprintMCP/Public",
|
||||
"Plugins/BlueprintMCP/Source/BlueprintMCP/Private",
|
||||
"Plugins/BlueprintMCP/Source/BlueprintMCP/Handlers",
|
||||
"Plugins/BlueprintMCP/Source/BlueprintMCP/HalfBaked",
|
||||
"Plugins/UEWingman/Source/UEWingman/Public",
|
||||
"Plugins/UEWingman/Source/UEWingman/Private",
|
||||
"Plugins/UEWingman/Source/UEWingman/Handlers",
|
||||
"Plugins/UEWingman/Source/UEWingman/HalfBaked",
|
||||
]
|
||||
|
||||
# Files to skip (relative to project root).
|
||||
|
||||
Reference in New Issue
Block a user