Files
UnrealEngine/Engine/Source/Editor/BlueprintGraph/Classes/BlueprintNodeBinder.h
2025-05-18 13:04:45 +08:00

277 lines
6.4 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Templates/Casts.h"
#include "Templates/Requires.h"
#include "UObject/Object.h"
#include "UObject/WeakObjectPtr.h"
#include "UObject/WeakFieldPtr.h"
#include <type_traits>
class UEdGraphNode;
class FBindingObject
{
TObjectPtr<UObject> Object;
FField* Field;
bool bIsUObject;
public:
FBindingObject()
: bIsUObject(false)
{}
template <
typename T
UE_REQUIRES(std::is_convertible_v<T, UObject*>)
>
FBindingObject(T InObject)
: Object(InObject)
, bIsUObject(true)
{}
FBindingObject(FField* InField)
: Field(InField)
, bIsUObject(false)
{}
FBindingObject(const FFieldVariant& InFieldOrObject)
{
bIsUObject = InFieldOrObject.IsUObject();
if (bIsUObject)
{
Object = InFieldOrObject.ToUObject();
}
else
{
Field = InFieldOrObject.ToField();
}
}
template <
typename T
UE_REQUIRES(std::is_convertible_v<T, UObject*>)
>
FBindingObject& operator=(T InObject)
{
Object = ImplicitConv<UObject*>(InObject);
Field = nullptr;
bIsUObject = true;
return *this;
}
FBindingObject& operator=(FField* InField)
{
Object = nullptr;
Field = InField;
bIsUObject = false;
return *this;
}
FBindingObject& operator=(TYPE_OF_NULLPTR)
{
Object = nullptr;
Field = nullptr;
return *this;
}
bool IsUObject() const
{
return bIsUObject;
}
bool IsValid() const
{
return bIsUObject ? Object != nullptr : Field != nullptr;
}
FName GetFName() const
{
return bIsUObject ? Object->GetFName() : Field->GetFName();
}
FString GetName() const
{
return bIsUObject ? Object->GetName() : Field->GetName();
}
FString GetPathName() const
{
return bIsUObject ? Object->GetPathName() : Field->GetPathName();
}
FString GetFullName() const
{
return bIsUObject ? Object->GetFullName() : Field->GetFullName();
}
bool IsA(const UClass* InClass) const
{
return bIsUObject && Object != nullptr && Object->IsA(InClass);
}
bool IsA(const FFieldClass* InClass) const
{
return !bIsUObject && Field != nullptr && Field->IsA(InClass);
}
template <typename T>
bool IsA() const
{
if constexpr (std::is_base_of_v<UObject, T>)
{
if (bIsUObject && Object)
{
return Object->IsA(T::StaticClass());
}
}
else
{
if (!bIsUObject && Field != nullptr)
{
return Field->IsA(T::StaticClass());
}
}
return false;
}
template <typename T>
T* Get() const
{
if constexpr (std::is_base_of_v<UObject, T>)
{
if (bIsUObject && Object)
{
return Cast<T>(Object);
}
}
else
{
if (!bIsUObject && Field != nullptr)
{
return CastField<T>(Field);
}
}
return nullptr;
}
friend uint32 GetTypeHash(const FBindingObject& BindingObject)
{
return BindingObject.bIsUObject ? GetTypeHash(BindingObject.Object) : GetTypeHash(BindingObject.Field);
}
bool operator==(const FBindingObject &Other) const
{
return bIsUObject == Other.bIsUObject && Object == Other.Object && Field == Other.Field;
}
bool operator!=(const FBindingObject &Other) const
{
return bIsUObject != Other.bIsUObject || Object != Other.Object || Field != Other.Field;
}
friend bool operator==(const FBindingObject &Lhs, const UObject* Rhs)
{
return Lhs.IsUObject() && Lhs.Object == Rhs;
}
friend bool operator!=(const FBindingObject &Lhs, const UObject* Rhs)
{
return !Lhs.IsUObject() || Lhs.Object != Rhs;
}
friend bool operator==(const UObject* Lhs, const FBindingObject &Rhs)
{
return Rhs.IsUObject() && Rhs.Object == Lhs;
}
friend bool operator!=(const UObject* Lhs, const FBindingObject &Rhs)
{
return !Rhs.IsUObject() || Rhs.Object != Lhs;
}
friend bool operator==(const FBindingObject &Lhs, const FField* Rhs)
{
return !Lhs.IsUObject() && Lhs.Field == Rhs;
}
friend bool operator!=(const FBindingObject &Lhs, const FField* Rhs)
{
return Lhs.IsUObject() || Lhs.Field != Rhs;
}
friend bool operator==(const FField* Lhs, const FBindingObject &Rhs)
{
return !Rhs.IsUObject() && Rhs.Field == Lhs;
}
friend bool operator!=(const FField* Lhs, const FBindingObject &Rhs)
{
return Rhs.IsUObject() || Rhs.Field != Lhs;
}
friend bool operator==(const FBindingObject &Lhs, TYPE_OF_NULLPTR)
{
return Lhs.IsUObject() ? Lhs.Object == nullptr : Lhs.Field == nullptr;
}
friend bool operator!=(const FBindingObject &Lhs, TYPE_OF_NULLPTR)
{
return Lhs.IsUObject() ? Lhs.Object != nullptr : Lhs.Field != nullptr;
}
friend bool operator==(TYPE_OF_NULLPTR, const FBindingObject &Rhs)
{
return Rhs.IsUObject() ? Rhs.Object == nullptr : Rhs.Field == nullptr;
}
friend bool operator!=(TYPE_OF_NULLPTR, const FBindingObject &Rhs)
{
return Rhs.IsUObject() ? Rhs.Object != nullptr : Rhs.Field != nullptr;
}
void AddStructReferencedObjects(FReferenceCollector& Collector);
};
template<>
struct TStructOpsTypeTraits<FBindingObject> : public TStructOpsTypeTraitsBase2<FBindingObject>
{
enum
{
WithAddStructReferencedObjects = true,
};
};
class IBlueprintNodeBinder
{
public:
/** */
typedef TSet< FBindingObject > FBindingSet;
public:
/**
* Checks to see if the specified object can be bound by this.
*
* @param BindingCandidate The object you want to check for.
* @return True if BindingCandidate can be bound by this controller, false if not.
*/
virtual bool IsBindingCompatible(FBindingObject BindingCandidate) const = 0;
/**
* Determines if this will accept more than one binding (used to block multiple
* bindings from being applied to nodes that can only have one).
*
* @return True if this will accept multiple bindings, otherwise false.
*/
virtual bool CanBindMultipleObjects() const = 0;
/**
* Attempts to bind all bindings to the supplied node.
*
* @param Node The node you want bound to.
* @return True if all bindings were successfully applied, false if any failed.
*/
bool ApplyBindings(UEdGraphNode* Node, FBindingSet const& Bindings) const
{
uint32 BindingCount = 0;
for (const FBindingObject& Binding : Bindings)
{
if (Binding.IsValid() && BindToNode(Node, Binding))
{
++BindingCount;
if (!CanBindMultipleObjects())
{
break;
}
}
}
return (BindingCount == Bindings.Num());
}
protected:
/**
* Attempts to apply the specified binding to the supplied node.
*
* @param Node The node you want bound.
* @param Binding The binding you want applied to Node.
* @return True if the binding was successful, false if not.
*/
virtual bool BindToNode(UEdGraphNode* Node, FBindingObject Binding) const = 0;
};