Compare commits

...

2 Commits

11 changed files with 131 additions and 69 deletions

View File

@@ -24,7 +24,7 @@ class UWing_Create_MaterialInstance : public UWingHandler
public: public:
UPROPERTY(EditAnywhere, meta=(Description="Full asset path for the new Material Instance (e.g. '/Game/Materials/MI_GoldShiny')")) UPROPERTY(EditAnywhere, meta=(Description="Full asset path for the new Material Instance (e.g. '/Game/Materials/MI_GoldShiny')"))
FString AssetPath; FString Path;
UPROPERTY(EditAnywhere, meta=(Description="Parent material package path (Material or Material Instance)")) UPROPERTY(EditAnywhere, meta=(Description="Parent material package path (Material or Material Instance)"))
FString ParentMaterial; FString ParentMaterial;
@@ -38,7 +38,7 @@ public:
virtual void Handle() override virtual void Handle() override
{ {
// Verify that the asset path is valid and available. // Verify that the asset path is valid and available.
if (!WingFactories::CheckNewAssetPath(AssetPath, WingOut::Stdout)) return; if (!WingFactories::CheckNewAssetPath(Path, WingOut::Stdout)) return;
// Load parent material by package path. // Load parent material by package path.
WingFetcher F(WingOut::Stdout); WingFetcher F(WingOut::Stdout);
@@ -50,7 +50,7 @@ public:
NewObject<UMaterialInstanceConstantFactoryNew>(); NewObject<UMaterialInstanceConstantFactoryNew>();
if (!WingUtils::CheckNewObjectNotNull( if (!WingUtils::CheckNewObjectNotNull(
Factory, TEXT("factory"), WingOut::Stdout)) return; Factory, TEXT("factory"), WingOut::Stdout)) return;
UObject* MIO = WingFactories::CreateAsset(AssetPath, UObject* MIO = WingFactories::CreateAsset(Path,
Factory, UMaterialInstanceConstant::StaticClass(), WingOut::Stdout); Factory, UMaterialInstanceConstant::StaticClass(), WingOut::Stdout);
if (!MIO) return; if (!MIO) return;

View File

@@ -53,8 +53,13 @@ public:
{ {
// Use the material editor's DeleteNodes to properly remove // Use the material editor's DeleteNodes to properly remove
// both the graph node and the underlying material expression. // both the graph node and the underlying material expression.
IMaterialEditor* MatEditor = F.CastEditor<UMaterial, IMaterialEditor>(); UMaterial* Material = F.CastAsset<UMaterial>();
if (!MatEditor) return; if (!Material) return;
IAssetEditorInstance* Editor = WingUtils::CheckOpenEditorForAsset(Material, WingOut::Stdout);
if (!Editor) return;
IMaterialEditor* MatEditor = static_cast<IMaterialEditor*>(Editor);
MatEditor->DeleteNodes({FoundNode}); MatEditor->DeleteNodes({FoundNode});
} }
else else

View File

@@ -4,6 +4,7 @@
#include "WingHandler.h" #include "WingHandler.h"
#include "WingServer.h" #include "WingServer.h"
#include "WingFetcher.h" #include "WingFetcher.h"
#include "WingPinReference.h"
#include "WingProperty.h" #include "WingProperty.h"
#include "WingUtils.h" #include "WingUtils.h"
#include "EdGraph/EdGraphPin.h" #include "EdGraph/EdGraphPin.h"
@@ -56,7 +57,9 @@ public:
void HandleK2Entry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj, const UEdGraphSchema_K2* K2Schema) void HandleK2Entry(const FSetNodeDefaultEntry& Entry, UEdGraph* GraphObj, const UEdGraphSchema_K2* K2Schema)
{ {
WingFetcher F(GraphObj, WingOut::Stdout); WingFetcher F(GraphObj, WingOut::Stdout);
UEdGraphPin* Pin = F.Node(Entry.Node).Pin(Entry.Name).Cast<UEdGraphPin>(); UWingPinReference* PinRef = F.Node(Entry.Node).Pin(Entry.Name).Cast<UWingPinReference>();
if (!PinRef) return;
UEdGraphPin* Pin = PinRef->CheckGetPin(WingOut::Stdout);
if (!Pin) return; if (!Pin) return;
UEdGraphNode* Node = Pin->GetOwningNode(); UEdGraphNode* Node = Pin->GetOwningNode();

View File

@@ -4,6 +4,7 @@
#include "WingServer.h" #include "WingServer.h"
#include "WingHandler.h" #include "WingHandler.h"
#include "WingFetcher.h" #include "WingFetcher.h"
#include "WingPinReference.h"
#include "WingProperty.h" #include "WingProperty.h"
#include "WingUtils.h" #include "WingUtils.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
@@ -64,11 +65,15 @@ public:
continue; continue;
WingFetcher FS(G, WingOut::Stdout); WingFetcher FS(G, WingOut::Stdout);
UEdGraphPin* SourcePin = FS.Walk(Entry.SourcePin).Cast<UEdGraphPin>(); UWingPinReference* SourcePinRef = FS.Walk(Entry.SourcePin).Cast<UWingPinReference>();
if (!SourcePinRef) continue;
UEdGraphPin* SourcePin = SourcePinRef->CheckGetPin(WingOut::Stdout);
if (!SourcePin) continue; if (!SourcePin) continue;
WingFetcher FT(G, WingOut::Stdout); WingFetcher FT(G, WingOut::Stdout);
UEdGraphPin* TargetPin = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>(); UWingPinReference* TargetPinRef = FT.Walk(Entry.TargetPin).Cast<UWingPinReference>();
if (!TargetPinRef) continue;
UEdGraphPin* TargetPin = TargetPinRef->CheckGetPin(WingOut::Stdout);
if (!TargetPin) continue; if (!TargetPin) continue;
const UEdGraphSchema* Schema = G->GetSchema(); const UEdGraphSchema* Schema = G->GetSchema();

View File

@@ -4,6 +4,7 @@
#include "WingServer.h" #include "WingServer.h"
#include "WingHandler.h" #include "WingHandler.h"
#include "WingFetcher.h" #include "WingFetcher.h"
#include "WingPinReference.h"
#include "WingProperty.h" #include "WingProperty.h"
#include "WingUtils.h" #include "WingUtils.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
@@ -63,7 +64,9 @@ public:
if (!FWingProperty::PopulateFromJson(EntryProps, *DiscVal, false, WingOut::Stdout)) continue; if (!FWingProperty::PopulateFromJson(EntryProps, *DiscVal, false, WingOut::Stdout)) continue;
WingFetcher FP(G, WingOut::Stdout); WingFetcher FP(G, WingOut::Stdout);
UEdGraphPin* Pin = FP.Walk(Entry.Pin).Cast<UEdGraphPin>(); UWingPinReference* PinRef = FP.Walk(Entry.Pin).Cast<UWingPinReference>();
if (!PinRef) continue;
UEdGraphPin* Pin = PinRef->CheckGetPin(WingOut::Stdout);
if (!Pin) continue; if (!Pin) continue;
int32 DisconnectedCount = 0; int32 DisconnectedCount = 0;
@@ -71,7 +74,9 @@ public:
if (!Entry.TargetPin.IsEmpty()) if (!Entry.TargetPin.IsEmpty())
{ {
WingFetcher FT(G, WingOut::Stdout); WingFetcher FT(G, WingOut::Stdout);
UEdGraphPin* Target = FT.Walk(Entry.TargetPin).Cast<UEdGraphPin>(); UWingPinReference* TargetRef = FT.Walk(Entry.TargetPin).Cast<UWingPinReference>();
if (!TargetRef) continue;
UEdGraphPin* Target = TargetRef->CheckGetPin(WingOut::Stdout);
if (!Target) continue; if (!Target) continue;
if (!Pin->LinkedTo.Contains(Target)) if (!Pin->LinkedTo.Contains(Target))

View File

@@ -3,6 +3,7 @@
#include "WingHandler.h" #include "WingHandler.h"
#include "WingUtils.h" #include "WingUtils.h"
#include "WingActorComponent.h" #include "WingActorComponent.h"
#include "WingPinReference.h"
#include "Engine/Blueprint.h" #include "Engine/Blueprint.h"
#include "EdGraph/EdGraph.h" #include "EdGraph/EdGraph.h"
#include "EdGraph/EdGraphNode.h" #include "EdGraph/EdGraphNode.h"
@@ -18,7 +19,6 @@
#include "WidgetBlueprint.h" #include "WidgetBlueprint.h"
#include "Blueprint/WidgetTree.h" #include "Blueprint/WidgetTree.h"
#include "Components/Widget.h" #include "Components/Widget.h"
#include "Subsystems/AssetEditorSubsystem.h"
#include "WingServer.h" #include "WingServer.h"
#include "WingManual.h" #include "WingManual.h"
@@ -39,30 +39,19 @@ void WingFetcher::SetObj(UObject* InObj)
if (!bSkipNotify) if (!bSkipNotify)
UWingServer::AddTouchedObject(InObj); UWingServer::AddTouchedObject(InObj);
Obj.Reset(InObj); Obj.Reset(InObj);
ResultPin = nullptr;
}
void WingFetcher::SetPin(UEdGraphPin* InPin)
{
ResultPin = InPin;
Obj.Reset();
} }
WingFetcher& WingFetcher::SetError() WingFetcher& WingFetcher::SetError()
{ {
bError = true; bError = true;
Obj.Reset(); Obj.Reset();
ResultPin = nullptr;
OriginalAsset.Reset(); OriginalAsset.Reset();
Editor = nullptr;
return *this; return *this;
} }
void WingFetcher::PathFailed(const TCHAR* Expected) void WingFetcher::PathFailed(const TCHAR* Expected)
{ {
if (ResultPin) if (Obj)
Errors.Printf(TEXT("ERROR: Path specifies a pin, but expected %s\n"), Expected);
else if (Obj)
Errors.Printf(TEXT("ERROR: Path specifies a %s, but expected %s\n"), *Obj.Get()->GetClass()->GetName(), Expected); Errors.Printf(TEXT("ERROR: Path specifies a %s, but expected %s\n"), *Obj.Get()->GetClass()->GetName(), Expected);
else else
Errors.Printf(TEXT("ERROR: Path led to a null pointer\n")); Errors.Printf(TEXT("ERROR: Path led to a null pointer\n"));
@@ -72,9 +61,7 @@ void WingFetcher::PathFailed(const TCHAR* Expected)
WingFetcher& WingFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expected) WingFetcher& WingFetcher::TypeMismatch(const TCHAR* Walker, const TCHAR* Expected)
{ {
if (ResultPin) if (Obj)
Errors.Printf(TEXT("ERROR: Input to '%s' is a pin, but expected %s\n"), Walker, Expected);
else if (Obj)
Errors.Printf(TEXT("ERROR: Input to '%s' is %s, but expected %s\n"), Walker, *Obj.Get()->GetClass()->GetName(), Expected); Errors.Printf(TEXT("ERROR: Input to '%s' is %s, but expected %s\n"), Walker, *Obj.Get()->GetClass()->GetName(), Expected);
else else
Errors.Printf(TEXT("ERROR: Path led to a null pointer\n")); Errors.Printf(TEXT("ERROR: Path led to a null pointer\n"));
@@ -105,7 +92,7 @@ WingFetcher& WingFetcher::Walk(const FString& Path)
for (int32 i = 0; i < Segments.Num(); i++) for (int32 i = 0; i < Segments.Num(); i++)
{ {
if (!Obj && !ResultPin) if (!Obj)
{ {
Asset(Segments[i]); Asset(Segments[i]);
if (bError) return *this; if (bError) return *this;
@@ -156,26 +143,20 @@ WingFetcher& WingFetcher::Asset(const FString& PackagePath)
OriginalAsset.Reset(Obj.Get()); OriginalAsset.Reset(Obj.Get());
// Open the editor for this asset (or bring it to front if already open). // If this is a material, open the editor and get the transient copy.
UAssetEditorSubsystem* Sub = GEditor->GetEditorSubsystem<UAssetEditorSubsystem>(); // If it's not a material, try to open the editor, but it's okay if we can't.
if (!Sub || !Sub->OpenEditorForAsset(Obj.Get()))
{
Errors.Printf(TEXT("ERROR: Could not open editor for '%s'\n"), *PackagePath);
return SetError();
}
Editor = Sub->FindEditorForAsset(OriginalAsset.Get(), false);
if (!Editor)
{
Errors.Printf(TEXT("ERROR: Could not find editor instance for '%s'\n"), *PackagePath);
return SetError();
}
// If this is a material, use the editor's transient copy.
if (UMaterial* Mat = ::Cast<UMaterial>(Obj.Get())) if (UMaterial* Mat = ::Cast<UMaterial>(Obj.Get()))
{ {
IAssetEditorInstance* Editor = WingUtils::CheckOpenEditorForAsset(OriginalAsset.Get(), Errors);
if (!Editor) return SetError();
IMaterialEditor *MatEditor = static_cast<IMaterialEditor*>(Editor); IMaterialEditor *MatEditor = static_cast<IMaterialEditor*>(Editor);
SetObj(MatEditor->GetMaterialInterface()->GetBaseMaterial()); SetObj(MatEditor->GetMaterialInterface()->GetBaseMaterial());
} }
else
{
WingUtils::CheckOpenEditorForAsset(OriginalAsset.Get(), nullptr);
}
return *this; return *this;
} }
@@ -287,7 +268,10 @@ WingFetcher& WingFetcher::Pin(const FString& Value)
} }
return SetError(); return SetError();
} }
SetPin(Found); UWingPinReference* Ref = NewObject<UWingPinReference>();
Ref->Node = N;
Ref->PinName = Found->GetFName();
SetObj(Ref);
return *this; return *this;
} }

View File

@@ -0,0 +1,33 @@
#include "WingPinReference.h"
#include "WingUtils.h"
#include "EdGraph/EdGraphNode.h"
#include "EdGraph/EdGraphPin.h"
UEdGraphPin* UWingPinReference::GetPin() const
{
if (!Node) return nullptr;
for (UEdGraphPin* Pin : Node->Pins)
{
if (Pin && Pin->GetFName() == PinName) return Pin;
}
return nullptr;
}
UEdGraphPin* UWingPinReference::CheckGetPin(WingOut Errors) const
{
if (!Node)
{
Errors.Print(TEXT("ERROR: Pin reference has no node\n"));
return nullptr;
}
UEdGraphPin* Pin = GetPin();
if (!Pin)
{
Errors.Printf(TEXT("ERROR: Pin '%s' no longer exists on node '%s'\n"),
*WingUtils::ExternalizeID(PinName), *WingUtils::FormatName(Node));
return nullptr;
}
return Pin;
}

View File

@@ -490,6 +490,30 @@ UObject *WingUtils::GetGeneratedCDO(UBlueprint *BP)
return BP->GeneratedClass->GetDefaultObject(); return BP->GeneratedClass->GetDefaultObject();
} }
// ============================================================
// Editor helpers
// ============================================================
IAssetEditorInstance* WingUtils::CheckOpenEditorForAsset(UObject* Asset, WingOut Errors)
{
const FString AssetPath = Asset ? Asset->GetPathName() : TEXT("null");
UAssetEditorSubsystem* Sub = GEditor ? GEditor->GetEditorSubsystem<UAssetEditorSubsystem>() : nullptr;
if (!Sub || !Sub->OpenEditorForAsset(Asset))
{
Errors.Printf(TEXT("ERROR: Could not open editor for '%s'\n"), *AssetPath);
return nullptr;
}
IAssetEditorInstance* Editor = Sub->FindEditorForAsset(Asset, false);
if (!Editor)
{
Errors.Printf(TEXT("ERROR: Could not find editor instance for '%s'\n"), *AssetPath);
return nullptr;
}
return Editor;
}
// ============================================================ // ============================================================
// Material helpers // Material helpers
// ============================================================ // ============================================================

View File

@@ -4,8 +4,6 @@
#include "UObject/StrongObjectPtr.h" #include "UObject/StrongObjectPtr.h"
#include "WingUtils.h" #include "WingUtils.h"
class UEdGraphPin;
class IAssetEditorInstance;
struct FWalker; struct FWalker;
// WingFetcher: Load an Asset and find an object within it. // WingFetcher: Load an Asset and find an object within it.
@@ -96,18 +94,6 @@ public:
return ::Cast<T>(OriginalAsset.Get()); return ::Cast<T>(OriginalAsset.Get());
} }
// When an asset is loaded, an editor is automatically
// opened. Get the editor. You must specify the type
// that you expect the asset to be, and the type to cast
// the editor to. Does not generate errors.
//
template<class AssetType, class EditorType>
EditorType* CastEditor()
{
if (!CheckAssetIsA(AssetType::StaticClass())) return nullptr;
return static_cast<EditorType*>(Editor);
}
// Calling SkipNotify disables change notifications // Calling SkipNotify disables change notifications
// for objects visited by this fetcher. Useful for // for objects visited by this fetcher. Useful for
// read-only operations that don't modify anything. // read-only operations that don't modify anything.
@@ -129,11 +115,9 @@ private:
// The Current Object. Only one of these can be non-null. // The Current Object. Only one of these can be non-null.
TStrongObjectPtr<UObject> Obj; TStrongObjectPtr<UObject> Obj;
UEdGraphPin* ResultPin = nullptr;
// The Starting Asset and the Editor we Opened. // The Starting Asset.
TStrongObjectPtr<UObject> OriginalAsset; TStrongObjectPtr<UObject> OriginalAsset;
IAssetEditorInstance* Editor = nullptr;
// True if an error has occurred. // True if an error has occurred.
bool bError = false; bool bError = false;
@@ -145,17 +129,9 @@ private:
// Internal methods. // Internal methods.
using WalkFunc = WingFetcher& (WingFetcher::*)(const FString&); using WalkFunc = WingFetcher& (WingFetcher::*)(const FString&);
void SetObj(UObject* InObj); void SetObj(UObject* InObj);
void SetPin(UEdGraphPin* InPin);
WingFetcher& SetError(); WingFetcher& SetError();
void PathFailed(const TCHAR *Kind); void PathFailed(const TCHAR *Kind);
WingFetcher& TypeMismatch(const TCHAR* Walker, const TCHAR* Expected); WingFetcher& TypeMismatch(const TCHAR* Walker, const TCHAR* Expected);
bool CheckAssetIsA(UClass* StaticClass); bool CheckAssetIsA(UClass* StaticClass);
WalkFunc GetWalker(const FString &Step); WalkFunc GetWalker(const FString &Step);
}; };
template<> inline UEdGraphPin* WingFetcher::Cast<UEdGraphPin>()
{
if (bError) return nullptr;
if (!ResultPin) PathFailed(TEXT("UEdGraphPin"));
return ResultPin;
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "WingHandler.h"
#include "WingPinReference.generated.h"
class UEdGraphNode;
class UEdGraphPin;
UCLASS()
class UWingPinReference : public UObject
{
GENERATED_BODY()
public:
UPROPERTY()
UEdGraphNode* Node = nullptr;
FName PinName;
UEdGraphPin* GetPin() const;
UEdGraphPin* CheckGetPin(WingOut Errors) const;
};

View File

@@ -24,6 +24,7 @@ class UAnimStateTransitionNode;
class IPropertyHandle; class IPropertyHandle;
class UScriptStruct; class UScriptStruct;
class UEnum; class UEnum;
class IAssetEditorInstance;
struct FBPInterfaceDescription; struct FBPInterfaceDescription;
struct FWingProperty; struct FWingProperty;
class IPropertyHandle; class IPropertyHandle;
@@ -247,6 +248,9 @@ public:
static TArray<UBlueprint*> GetAncestorBlueprints(UBlueprint *BP, bool OldestFirst = false); static TArray<UBlueprint*> GetAncestorBlueprints(UBlueprint *BP, bool OldestFirst = false);
static UObject *GetGeneratedCDO(UBlueprint *BP); static UObject *GetGeneratedCDO(UBlueprint *BP);
// ----- Editor helpers -----
static IAssetEditorInstance* CheckOpenEditorForAsset(UObject* Asset, WingOut Errors);
// ----- Material helpers ----- // ----- Material helpers -----
static void EnsureMaterialGraph(UMaterial* Material); static void EnsureMaterialGraph(UMaterial* Material);
@@ -277,4 +281,3 @@ public:
static bool CheckCanRename(UEdGraphNode* Node, const FString &Name, WingOut Errors); static bool CheckCanRename(UEdGraphNode* Node, const FString &Name, WingOut Errors);
static bool CheckNewObjectNotNull(UObject *Obj, const TCHAR *Kind, WingOut Errors); static bool CheckNewObjectNotNull(UObject *Obj, const TCHAR *Kind, WingOut Errors);
}; };