CommonDelegate解决方案

实现业务时,经常需要用到全局级别的 CommonDelegate

定义如下 UTestCommonDelegate,即可定义出 UTestCommonDelegate::GetDelegate()->OnTestEvent 这样的一个 Delegate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// TestCommonDelegate

UCLASS()
class UTestCommonDelegate : public UCommonDelegateBase
{
GENERATED_BODY()

public:
UFUNCTION()
static UTestCommonDelegate* GetDelegate()
{
return GetCommonDelegate<UTestCommonDelegate>();
}

public:
DECLARE_DELEGATE_AnyParams(FTestEvent, int32 /*IntVal*/);
FTestEvent OnTestEvent;
}

CommonDelegateBase

首先定义 UCommonDelegateBase 作为所有 Delegate 的基类;

1
2
3
4
5
6
7
// CommonDelegateBase

UCLASS(Abstract)
class UCommonDelegateBase : public UObject
{
GENERATED_BODY()
};

定义 GlobalCommonDelegates 用于存储全局的所有 Delegates

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
USTRUCT()
struct FCommonDelegates
{
GENERATED_BODY()

public:
TMap<TSubclassOf<UCommonDelegateBase>, UCommonDelegateBase*>* GetDelegateMap()
{
return &DelegateMap;
}

private:
UPROPERTY()
TMap<TSubclassOf<UCommonDelegateBase>, UCommonDelegateBase*> DelegateMap;
};


extern FCommonDelegates GlobalCommonDelegates;

GetDelegate 中尝试寻找或创建 Delegate,将其 AddToRoot

同时提供 DeleteAllCommonDelegates 在合适的时候(比如切换 World)调用,清空所有数据;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
template<class T>
typename TEnableIf<TIsDerivedFrom<T, UCommonDelegateBase>::Value, T*>::Type
GetCommonDelegate()
{
auto DelegateMap = GlobalCommonDelegates.GetDelegateMap();
if (DelegateMap == nullptr) return nullptr;

if (auto Delegate = DelegateMap->FindRef(T::StaticClass()); IsValid(Delegate))
{
return Cast<T>(Delegate);
}

auto NewDelegate = NewObject<T>();
NewDelegate->AddToRoot();
DelegateMap->FindOrAdd(T::StaticClass()) = NewDelegate;
return NewDelegate;
}

void DeleteAllCommonDelegates()
{
auto DelegateMap = GlobalCommonDelegates.GetDelegateMap();
if (DelegateMap == nullptr) return nullptr;

for (auto DelegatePair : *DelegateMap)
{
if (IsValid(DelegatePair.Value))
{
DelegatePair.Value->RemoveFromRoot();
}
}

DelegateMap->Empty();
}

DeclareAnyParams

一般的 DECLARE_DELEGATE 需要写明 Params 的个数;比如 DECLARE_MULTICAST_DELEGATE_OneParam,这里限定了 OneParam

实际上,可以看到在 Engine\Source\Runtime\Core\Public\Delegates\Delegate.h 中,支持添加 AnyParams

1
2
3
4
5
6
7
8
9
10
11
12
13
// Delegate.h

#define FUNC_DECLARE_DELEGATE( DelegateName, ReturnType, ... ) \
typedef TDelegate<ReturnType(__VA_ARGS__)> DelegateName;

#define FUNC_DECLARE_MULTICAST_DELEGATE( MulticastDelegateName, ReturnType, ... ) \
typedef TMulticastDelegate<ReturnType(__VA_ARGS__)> MulticastDelegateName;

#define FUNC_DECLARE_EVENT( OwningType, EventName, ReturnType, ... ) \
class EventName : public TMulticastDelegate<ReturnType(__VA_ARGS__)> \
{ \
friend class OwningType; \
};

于是可以对非 DYNAMICDELEGATE 添加声明,

直接在 Engine\Source\Runtime\Core\Public\Delegates\DelegateCombinations.h 中补充:

1
2
3
4
#define DECLARE_DELEGATE_AnyParams( DelegateName, ... ) FUNC_DECLARE_DELEGATE( DelegateName, void, __VA_ARGS__ )
#define DECLARE_MULTICAST_DELEGATE_AnyParams( DelegateName, ... ) FUNC_DECLARE_MULTICAST_DELEGATE( DelegateName, void, __VA_ARGS__ )
#define DECLARE_EVENT_AnyParams( OwningType, EventName, ... ) FUNC_DECLARE_EVENT( OwningType, EventName, void, __VA_ARGS__ )
#define DECLARE_DELEGATE_RetVal_AnyParams( ReturnValueType, DelegateName, ... ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType, __VA_ARGS__ )