Last active
May 20, 2019 18:46
-
-
Save SammyJames/9ece78e3a11aec316194b806016744bd to your computer and use it in GitHub Desktop.
A wrapper to handle native and script delegates
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "Delegate.h" | |
#include "Delegates/IDelegateInstance.h" | |
#include "LogMacros.h" | |
#include "UnrealTypeTraits.h" | |
namespace Private | |
{ | |
template <bool, class T> | |
struct TMultiDelUnwrapBase | |
{ | |
}; | |
template <class T> | |
struct TMultiDelUnwrapBase<true, T> | |
{ | |
template <class> | |
struct Unwrap; | |
template <class WeakType, class... Args> | |
struct Unwrap<TBaseDynamicDelegate<WeakType, void, Args...>*> | |
{ | |
using Base = TMulticastDelegate<void, Args...>; | |
}; | |
using BaseType = typename Unwrap<typename T::FDelegate*>::Base; | |
}; | |
template <class T> | |
struct TMultiDelTypeUnwrap | |
: TMultiDelUnwrapBase< | |
TPointerIsConvertibleFromTo<T, TMulticastScriptDelegate<FWeakObjectPtr>>::Value, | |
T> | |
{ | |
}; | |
} // namespace Private | |
/** | |
* A unified delegate that takes a multicast script (dynamic) delegate and generates a native | |
* delegate from that type owned by this struct. Construct with a reference to the script delegate, | |
* and broadcast on this struct to invoke both native and script. | |
* @tparam ScriptType a multicast script (dynamic) delegate | |
*/ | |
template <class ScriptType> | |
struct TUnifiedMulticastDelegate | |
{ | |
using THelper = typename Private::TMultiDelTypeUnwrap<ScriptType>; | |
TUnifiedMulticastDelegate() = delete; | |
TUnifiedMulticastDelegate(const TUnifiedMulticastDelegate&) = delete; | |
#if !NO_LOGGING | |
~TUnifiedMulticastDelegate() | |
{ | |
UE_CLOG(m_nNativeInvocations != m_nScriptInvocations, | |
LogTemp, | |
Warning, | |
TEXT("Native delegate invocation count is not equal to script delegate invocation " | |
"count: native = %d, script = %d"), | |
m_nNativeInvocations, | |
m_nScriptInvocations); | |
} | |
#else | |
~TUnifiedMulticastDelegate() = default; | |
#endif // !NO_LOGGING | |
TUnifiedMulticastDelegate(ScriptType& InScript) | |
: m_NativeDelegate() | |
, m_pScriptDelegate(&InScript) | |
{ | |
} | |
TUnifiedMulticastDelegate(TUnifiedMulticastDelegate&& Other) | |
: m_NativeDelegate(MoveTemp(Other.m_NativeDelegate)) | |
, m_pScriptDelegate(Other.m_pScriptDelegate) | |
{ | |
m_pScriptDelegate = nullptr; | |
} | |
TUnifiedMulticastDelegate& operator=(TUnifiedMulticastDelegate&& Other) | |
{ | |
m_NativeDelegate = MoveTemp(Other.m_NativeDelegate); | |
m_pScriptDelegate = Other.m_pScriptDelegate; | |
Other.m_pScriptDelegate = nullptr; | |
return *this; | |
} | |
template <class Object, | |
class... Args, | |
class = typename TEnableIf<TIsDerivedFrom<Object, UObject>::IsDerived, Object>::Type> | |
FDelegateHandle Add(Object* pObject, void (Object::*InMethod)(Args...)) | |
{ | |
return m_NativeDelegate.template AddUObject<Object>(pObject, InMethod); | |
} | |
template <class Object, | |
class... Args, | |
class = typename TEnableIf<TIsDerivedFrom<Object, UObject>::IsDerived, Object>::Type> | |
FDelegateHandle Add(Object* pObject, void (Object::*InMethod)(Args...) const) | |
{ | |
return m_NativeDelegate.template AddUObject<Object>(pObject, InMethod); | |
} | |
template <class Object, class... Args> | |
FDelegateHandle Add(const TSharedPtr<Object>& pObject, void (Object::*InMethod)(Args...)) | |
{ | |
return m_NativeDelegate.template AddSP<Object>(pObject, InMethod); | |
} | |
template <class Object, class... Args> | |
FDelegateHandle Add(const TSharedPtr<Object>& pObject, void (Object::*InMethod)(Args...) const) | |
{ | |
return m_NativeDelegate.template AddSP<Object>(pObject, InMethod); | |
} | |
template <class Object, class... Args> | |
FDelegateHandle | |
Add(typename TEnableIf<!TIsDerivedFrom<Object, UObject>::IsDerived, Object>::Type* pObject, | |
void (Object::*InMethod)(Args...)) | |
{ | |
return m_NativeDelegate.template AddRaw<Object>(pObject, InMethod); | |
} | |
template <class Object, class... Args> | |
FDelegateHandle | |
Add(typename TEnableIf<!TIsDerivedFrom<Object, UObject>::IsDerived, Object>::Type* pObject, | |
void (Object::*InMethod)(Args...) const) | |
{ | |
return m_NativeDelegate.template AddRaw<Object>(pObject, InMethod); | |
} | |
template <class Functor> | |
FDelegateHandle Add(Functor&& InFunc) | |
{ | |
return m_NativeDelegate.template AddLambda<Functor>(Forward<Functor>(InFunc)); | |
} | |
template <class... Args> | |
FDelegateHandle Add(void (*InMethod)(Args...)) | |
{ | |
return m_NativeDelegate.template AddStatic(InMethod); | |
} | |
void Remove(FDelegateHandle&& InHandle) | |
{ | |
if (InHandle.IsValid()) | |
{ | |
m_NativeDelegate.Remove(InHandle); | |
InHandle.Reset(); | |
} | |
} | |
template <class Object> | |
void RemoveAll(Object* pObject) | |
{ | |
m_NativeDelegate.RemoveAll(pObject); | |
} | |
template <class... Args> | |
void Broadcast(Args&&... InArgs) const | |
{ | |
if (m_NativeDelegate.IsBound()) | |
{ | |
#if !NO_LOGGING | |
++m_nNativeInvocations; | |
UE_LOG( | |
LogTemp, Log, TEXT("Invoking native delegate, count = %d"), m_nNativeInvocations); | |
#endif // !NO_LOGGING | |
m_NativeDelegate.Broadcast(Forward<Args>(InArgs)...); | |
} | |
if (m_pScriptDelegate && m_pScriptDelegate->IsBound()) | |
{ | |
#if !NO_LOGGING | |
++m_nScriptInvocations; | |
UE_LOG( | |
LogTemp, Log, TEXT("Invoking script delegate, count = %d"), m_nScriptInvocations); | |
#endif // !NO_LOGGING | |
m_pScriptDelegate->Broadcast(Forward<Args>(InArgs)...); | |
} | |
} | |
private: | |
typename THelper::BaseType m_NativeDelegate; | |
ScriptType* m_pScriptDelegate = nullptr; | |
#if !NO_LOGGING | |
mutable uint32 m_nNativeInvocations = 0u; | |
mutable uint32 m_nScriptInvocations = 0u; | |
#endif // !NO_LOGGING | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
using it like so: