全面理解UE4委托
UE4中的delegate(委托)常用于解耦不同对象之间的关联:委托的触发者不与监听者有直接关联,两者通过委托对象间接地建立联系
监听者通过将响应函数绑定到委托上,使得委托触发时立即收到通知,并进行相关逻辑处理
委托,又称代理,本质是一个特殊类的对象,它内部可以储存(一个或多个)函数指针、调用参数和返回值
委托的作用如同函数指针,但它更安全(支持编译期类型检查),而且更易于使用
UE4在DelegateCombinations.h提供了一些宏来方便开发者快速来自定义一个delegate类型
大致地使用流程如下:
① 使用DECLARE_*宏声明一个自定义delegate类型FDelegateXXX
② 声明一个FDelegateXXX类型的代理对象
③ 绑定需要执行的函数指针到代理对象上
④ 触发代理对象中的函数指针会立即执行
⑤ 不需要某个函数指针时,可将其从代理对象中解绑
UE4提供了五类Delegate:
名称 | 宏 |
是否支持反射 以及序列化 |
能否有返回值 |
是否支持 Payload参数 |
触发代理 | 绑定个数 | 支持的绑定实例类型 |
单播代理 |
DECLARE_DELEGATE_* DECLARE_DELEGATE_RetVal_* |
否 |
可以有 | 是 |
① 无返回值情况 bool ExecuteIfBound(...) void Execute(...) ② 有返回值情况 RetValue Execute(...) 注:RetValue为绑定函数 的返回值 |
1个 |
// BindStatic、CreateStatic ① Static函数 // BindRaw、CreateRaw ② 普通C++对象的成员函数 // BindLambda、CreateLambda ③ Lambda表达式 // BindWeakLambda、CreateWeakLambda ④ 与某个UObject对象关联的Lambda表达式 // BindSP、CreateSP ⑤ 共享引用包裹的普通C++对象的成员函数 // BindThreadSafeSP、CreateThreadSafeSP ⑥ 线程安全的共享引用包裹的普通C++对象的成员函数 // BindUObject、CreateUObject ⑦ UObject对象的成员函数 // BindUFunction、CreateUFunction ⑧ UObject对象的UFunction成员函数 |
多播代理 (组播代理) |
DECLARE_MULTICAST_DELEGATE_* | 否 | 无 | 是 | void Broadcast(...) | 多个 |
① Static函数 // AddStatic ② 普通C++对象的成员函数 // AddRaw ③ Lambda表达式 // AddLambda // AddWeakLambda ④ 与某个UObject对象关联的Lambda表达式 ⑤ 共享引用包裹的普通C++对象的成员函数 // AddSP // AddThreadSafeSP ⑥ 线程安全的共享引用包裹的普通C++对象的成员函数 ⑦ UObject对象的成员函数 // AddUObject ⑧ UObject对象的UFunction成员函数 // AddUFunction -------------------------------------- 另外,可以创建FDelegate对象,然后调用Add函数 |
事件 | DECLARE_EVENT_* | 否 | 无 | 是 | void Broadcast(...) | 多个 |
同上 |
动态代理 |
DECLARE_DYNAMIC_DELEGATE_* DECLARE_DYNAMIC_DELEGATE_RetVal_* |
是 |
可以有 | 否 |
① 无返回值情况 bool ExecuteIfBound(...) void Execute(...) ② 有返回值情况 RetValue Execute(...) 注:RetValue为绑定函数 的返回值 |
1个 |
// BindUFunction UObject对象的UFunction成员函数 -------------------------------------- 另外,可以使用BindDynamic宏来绑定 |
动态多播代理 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_* |
是 蓝图中可使用 |
无 | 否 | void Broadcast(...) | 多个 |
// Add函数、AddDynamic宏 // AddUnique函数、AddUniqueDynamic宏 UObject对象的UFunction成员函数 |
注1:Payload为代理绑定时传递的额外参数变量列表,这些参数会存储在代理对象内部;在触发代理时,Payload会紧跟着Execute、ExecuteInBound或Broadcast传入的参数之后,填充到绑定函数指针的参数列表中,然后执行
DECLARE_DELEGATE_OneParam(FTestDelegate, int); static void StaticDelegateProc(int nCode) { UE_LOG(LogTemp, Log, TEXT("StaticDelegateProc : %d"), nCode); } static void StaticDelegateProcTest(int nCode, float dis, FString txt) { UE_LOG(LogTemp, Log, TEXT("StaticDelegateProcTest : %d %f %s"), nCode, dis, *txt); } FTestDelegate DelegateObj1; DelegateObj1.BindStatic(StaticDelegateProc); DelegateObj1.ExecuteIfBound(1); // Payload示例 FTestDelegate DelegateObj2; DelegateObj2.BindStatic(StaticDelegateProcTest, 12.0f, FString(TEXT("Hello"))); // 12.0f、FString(TEXT("Hello"))为绑定时传入的Payload参数 DelegateObj2.ExecuteIfBound(2);
/******* 创建带参数的Timer *******/ UCLASS() class UDelegatepTimerTest : public UObject { GENERATED_BODY() public: void DelegateProc1(FString map) { UE_LOG(LogTemp, Log, TEXT("DelegateProc1 : %s"), *map); } void Test() { FTimerHandle TimeHandle; FTimerDelegate MyDelegate; MyDelegate.BindUObject(this, &UDelegatepTimerTest::DelegateProc1, FString(TEXT("FarmLand"))); GetWorld()->GetTimerManager().SetTimer(TimeHandle, MyDelegate, 5.0f, false); // 创建一个5.0s的一次性定时器 Payload示例 } };
注2:动态代理、动态多播代理不支持Payload,因此,绑定函数与代理对象的参数、返回值必须完全一致
下面为一些类型示例:
① 单播代理
DECLARE_DELEGATE( FSimpleDelegate ); // 无参、无返回值
DECLARE_DELEGATE_OneParam(FPakEncryptionKeyDelegate, uint8[32]); // 1个参数、无返回值
DECLARE_DELEGATE_TwoParams(FPakSigningKeysDelegate, TArray<uint8>&, TArray<uint8>&); // 2个参数、无返回值
DECLARE_DELEGATE_RetVal_ThreeParams(bool, FOnMountPak, const FString&, int32, IPlatformFile::FDirectoryVisitor*); // 3个参数、bool返回值
② 多播代理
DECLARE_MULTICAST_DELEGATE( FSimpleMulticastDelegate ); // 无参
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnTreeStarted, const UBehaviorTreeComponent&, const UBehaviorTree& ); // 2个参数
DECLARE_MULTICAST_DELEGATE_FourParams(FOnOpenURL, UIApplication*, NSURL*, NSString*, id); // 4个参数
③ 事件
DECLARE_EVENT(UWorld, FOnTickFlushEvent); // 无参
DECLARE_EVENT_OneParam(IWebBrowserWindow, FOnTitleChanged, FString); // 1个参数
④ 动态代理
DECLARE_DYNAMIC_DELEGATE(FOnGameWindowCloseButtonClickedDelegate); // 无参、无返回值
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAssetLoaded, class UObject*, Loaded); // 1个参数、无返回值
DECLARE_DYNAMIC_DELEGATE_RetVal(EMouseCursor::Type, FGetMouseCursor); // 无参、EMouseCursor::Type返回值
DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(UWidget*, FGenerateWidgetForObject, UObject*, Item); // 1个参数、UWidget*返回值
DECLARE_DYNAMIC_DELEGATE_RetVal_TwoParams(FEventReply, FOnPointerEvent, FGeometry, MyGeometry, const FPointerEvent&, MouseEvent); // 2个参数、FEventReply返回值
⑤ 动态多播代理
DECLARE_DYNAMIC_MULTICAST_DELEGATE( FLevelStreamingLoadedStatus ); // 无参
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLandedSignature, const FHitResult&, Hit); // 1个参数
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FMovementModeChangedSignature, class ACharacter*, Character, EMovementMode, PrevMovementMode, uint8, PreviousCustomMode); // 3个参数
单播代理
1. 定义代理类型
① 定义返回值为void含1个int类型参数的单播代理类型FCharacterDelegate
DECLARE_DELEGATE_OneParam(FCharacterDelegate, int); // TBaseDelegate<void, int>
② 定义返回值为bool含1个int类型参数的单播代理类型FCharacterDelegate_RetVal
DECLARE_DELEGATE_RetVal_OneParam(bool, FCharacterDelegate_RetVal, int); // TBaseDelegate<bool, int>
2. 声明代理对象
FCharacterDelegate CharacterDelegate;
FCharacterDelegate_RetVal CharacterDelegateRetVal;
以FCharacterDelegate为例,讲述单播代理的绑定、触发执行及存在的风险
/*** TPSProjectCharacter.h ***/ UCLASS() class UDelegatepTestClass : public UObject { GENERATED_BODY() protected: int m_nValue = 0; public: void DelegateProc1(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("DelegateProc1 : %d"), nCode); } UFUNCTION() void DelegateUFunctionProc1(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("DelegateUFunctionProc1 : %d"), nCode); } }; class DelegateCppTestClass { int m_nValue = 0; public: void CppDelegateProc(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("CppDelegateProc : %d"), nCode); } void CppDelegateProc2(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("CppDelegateProc2 : %d"), nCode); } void CppDelegateProc3(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("CppDelegateProc3 : %d"), nCode); } void CppDelegateProc4(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("CppDelegateProc4 : %d"), nCode); } void CppDelegateProc5(int nCode) { this->m_nValue = nCode; UE_LOG(LogTemp, Log, TEXT("CppDelegateProc5 : %d"), nCode); } }; UCLASS(config=Game) class ATPSProjectCharacter : public ACharacter { GENERATED_BODY() public: static void StaticCharacterDelegateProc(int nCode); void OnBind(); void OnExecute(); void OnUnbind(); FCharacterDelegate CharacterDelegate1; FCharacterDelegate CharacterDelegate2; FCharacterDelegate CharacterDelegate3; FCharacterDelegate CharacterDelegate4; FCharacterDelegate CharacterDelegate5; FCharacterDelegate CharacterDelegate6; FCharacterDelegate CharacterDelegate7; FCharacterDelegate CharacterDelegate8; FCharacterDelegate CharacterDelegate9; FCharacterDelegate CharacterDelegate10; FCharacterDelegate CharacterDelegate11; FCharacterDelegate CharacterDelegate12; FCharacterDelegate CharacterDelegate13; }; /*** TPSProjectCharacter.cpp ***/ static void StaticDelegateProc(int nCode) { UE_LOG(LogTemp, Log, TEXT("StaticDelegateProc : %d"), nCode); } void ATPSProjectCharacter::StaticCharacterDelegateProc(int nCode) { UE_LOG(LogTemp, Log, TEXT("StaticCharacterDelegateProc : %d"), nCode); } void ATPSProjectCharacter::OnBind() { // Bind Static CharacterDelegate1.BindStatic(StaticDelegateProc); // 等价于CharacterDelegate1 = FCharacterDelegate::CreateStatic(StaticDelegateProc); CharacterDelegate2.BindStatic(ATPSProjectCharacter::StaticCharacterDelegateProc); // 等价于CharacterDelegate2 = FCharacterDelegate::CreateStatic(AMyTest1Character::StaticCharacterDelegateProc); // Bind Raw DelegateCppTestClass Obj1; CharacterDelegate3.BindRaw(&Obj1, &DelegateCppTestClass::CppDelegateProc); // 等价于CharacterDelegate3 = FCharacterDelegate::CreateRaw(&Obj1, &DelegateCppTestClass::CppDelegateProc); // Bind Lambda auto LambdaDelegateProc = [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("LambdaDelegateProc : %d"), nCode); }; CharacterDelegate4.BindLambda(LambdaDelegateProc); // 等价于CharacterDelegate4 = FCharacterDelegate::CreateLambda(LambdaDelegateProc); CharacterDelegate5.BindLambda( // 等价于CharacterDelegate5 = FCharacterDelegate::CreateLambda(...); [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("LambdaDelegateProc2 : %d"), nCode); } ); // Bind Weak Lambda auto WeakLambdaDelegateProc = [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateProc : %d"), nCode); }; UDelegatepTestClass* UObj1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegate6.BindWeakLambda(UObj1, WeakLambdaDelegateProc); // 等价于CharacterDelegate6 = FCharacterDelegate::CreateWeakLambda(UObj1, WeakLambdaDelegateProc); UDelegatepTestClass* UObj2 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegate7.BindWeakLambda( // 等价于CharacterDelegate7 = FCharacterDelegate::CreateWeakLambda(...); UObj2, [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateProc2 : %d"), nCode); } ); // Bind SP(Shared Pointer) TSharedRef<DelegateCppTestClass> ObjSP1 = MakeShareable(new DelegateCppTestClass()); CharacterDelegate8.BindSP(ObjSP1, &DelegateCppTestClass::CppDelegateProc2); // 等价于CharacterDelegate8 = FCharacterDelegate::CreateSP(ObjSP1, &DelegateCppTestClass::CppDelegateProc2); TSharedRef<DelegateCppTestClass> ObjSP2 = MakeShared<DelegateCppTestClass>(); CharacterDelegate9.BindSP(ObjSP2, &DelegateCppTestClass::CppDelegateProc3);// 等价于CharacterDelegate9 = FCharacterDelegate::CreateSP(ObjSP2, &DelegateCppTestClass::CppDelegateProc3); // Bind Thread Safe SP(Shared Pointer) 注:指定了ESPMode::ThreadSafe,会对SharedReferenceCount、WeakReferenceCount引用计数的进行原子操作,保证线程安全 TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeSP1 = MakeShareable(new DelegateCppTestClass()); CharacterDelegate10.BindThreadSafeSP(ObjSafeSP1, &DelegateCppTestClass::CppDelegateProc4); // 等价于CharacterDelegate10 = FCharacterDelegate::CreateThreadSafeSP(ObjSafeSP1, &DelegateCppTestClass::CppDelegateProc4); TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeSP2 = MakeShared<DelegateCppTestClass, ESPMode::ThreadSafe>(); CharacterDelegate11.BindThreadSafeSP(ObjSafeSP2, &DelegateCppTestClass::CppDelegateProc5);// 等价于CharacterDelegate11 = FCharacterDelegate::CreateThreadSafeSP(ObjSafeSP2, &DelegateCppTestClass::CppDelegateProc5); // Bind UObject UDelegatepTestClass* UObj3 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegate12.BindUObject(UObj3, &UDelegatepTestClass::DelegateProc1);// 等价于CharacterDelegate12 = FCharacterDelegate::CreateUObject(UObj3, &UDelegatepTestClass::DelegateProc1); // Bind UFunction UDelegatepTestClass* UObj4 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegate13.BindUFunction(UObj4, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1"))); // 等价于CharacterDelegate13 = FCharacterDelegate::CreateUFunction(UObj4, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1"))); } void ATPSProjectCharacter::OnExecute() { CharacterDelegate1.ExecuteIfBound(1); CharacterDelegate2.ExecuteIfBound(2); CharacterDelegate3.ExecuteIfBound(3); CharacterDelegate4.ExecuteIfBound(4); CharacterDelegate5.ExecuteIfBound(5); CharacterDelegate6.ExecuteIfBound(6); CharacterDelegate7.ExecuteIfBound(7); CharacterDelegate8.ExecuteIfBound(8); CharacterDelegate9.ExecuteIfBound(9); CharacterDelegate10.ExecuteIfBound(10); CharacterDelegate11.ExecuteIfBound(11); CharacterDelegate12.ExecuteIfBound(12); if (CharacterDelegate13.IsBound()) { CharacterDelegate13.Execute(13); } } void ATPSProjectCharacter::OnUnbind() { CharacterDelegate1.Unbind(); CharacterDelegate2.Unbind(); CharacterDelegate3.Unbind(); CharacterDelegate4.Unbind(); CharacterDelegate5.Unbind(); CharacterDelegate6.Unbind(); CharacterDelegate7.Unbind(); CharacterDelegate8.Unbind(); CharacterDelegate9.Unbind(); CharacterDelegate10.Unbind(); CharacterDelegate11.Unbind(); CharacterDelegate12.Unbind(); CharacterDelegate13.Unbind(); }
注1:BindRaw函数用于绑定普通c++对象的成员函数,若该c++对象已被销毁,触发代理执行该对象的成员函数,将会导致内存违规操作
注2:BindLambda函数用于绑定lambda表达式,若lambda表达式捕获外部变量已被销毁,触发代理执行lambda表达式,将会导致内存违规操作
注3:BindWeakLambda、BindUObject、BindUFunction绑定时会与一个UObject对象进行弱引用关联(不影响该对象被gc回收)
若UObject对象被gc回收,直接调用Execute触发代理,将会导致内存违规操作;可先调用IsBound或调用ExecuteIfBound触发代理来检查该UObject的有效性,再来执行代理
注4:BindSP、BindThreadSafeSP绑定时会与一个智能指针对象进行弱引用关联(不影响该对象的内存回收)
若智能指针对象的内存被回收,直接调用Execute触发代理,将会导致内存违规操作;可先调用IsBound或调用ExecuteIfBound触发代理来检查该智能指针对象的有效性,再来执行代理
注5:单播代理对象在被销毁时,会在其析构函数中调用Unbind进行解绑操作
注6:不同的绑定实例类型定义在:DelegateInstancesImpl.h
BindStatic(绑定实例类型为:TBaseStaticDelegateInstance)
BindRaw(绑定实例类型为:TBaseRawMethodDelegateInstance)
BindLambda(绑定实例类型为:TBaseFunctorDelegateInstance)
BindWeakLambda(绑定实例类型为:TWeakBaseFunctorDelegateInstance)
BindSP(绑定实例类型为:TBaseSPMethodDelegateInstance)
BindThreadSafeSP(绑定实例类型为:TBaseSPMethodDelegateInstance)
BindUObject(绑定实例类型为:TBaseUObjectMethodDelegateInstance)
BindUFunction(绑定实例类型为:TBaseUFunctionDelegateInstance)
多播代理(组播代理)
1. 定义返回值为void含1个int类型参数的多播代理类型FCharacterDelegate_Multicase
DECLARE_MULTICAST_DELEGATE_OneParam(FCharacterDelegate_Multicast, int); // TMulticastDelegate<void, int>
2. 声明代理对象
FCharacterDelegate_Multicast CharacterDelegateMulticast1;
以FCharacterDelegate_Multicast为例,讲述多播代理的绑定、触发执行及存在的风险
void ATPSProjectCharacter::OnDelegateMulticastTest() { // Add Static bool b1 = CharacterDelegateMulticast1.IsBound(); // false FDelegateHandle HandleMC1 = CharacterDelegateMulticast1.AddStatic(StaticDelegateProc); // 绑定实例个数为:1 CharacterDelegateMulticast1.AddStatic(ATPSProjectCharacter::StaticCharacterDelegateProc); // 绑定实例个数为:2 bool b2 = CharacterDelegateMulticast1.IsBound(); // true bool b3 = CharacterDelegateMulticast1.IsBoundToObject(this); // false CharacterDelegateMulticast1.Remove(HandleMC1); // 绑定实例个数为:1 FCharacterDelegate_Multicast::FDelegate MC1 = FCharacterDelegate_Multicast::FDelegate::CreateStatic(StaticDelegate2Proc); CharacterDelegateMulticast1.Add(MC1); // 绑定实例个数为:2 CharacterDelegateMulticast1.Broadcast(100); // 执行绑定实例列表(共2个) 注:执行顺序可能与函数的添加顺序不相同 // Add Raw DelegateCppTestClass ObjMC1; CharacterDelegateMulticast2.AddRaw(&ObjMC1, &DelegateCppTestClass::CppDelegateProc); // 绑定实例个数为:1 CharacterDelegateMulticast2.AddRaw(&ObjMC1, &DelegateCppTestClass::CppDelegateProc2); // 绑定实例个数为:2 CharacterDelegateMulticast2.AddStatic(ATPSProjectCharacter::StaticCharacterDelegateProc); // 绑定实例个数为:3 bool b4 = CharacterDelegateMulticast2.IsBoundToObject(&ObjMC1); // true CharacterDelegateMulticast2.RemoveAll(&ObjMC1); // CppDelegateProc、CppDelegateProc2被删除,绑定实例个数为:1 bool b5 = CharacterDelegateMulticast2.IsBoundToObject(&ObjMC1); // false CharacterDelegateMulticast2.Broadcast(101); // 执行绑定实例列表(共1个) 注:执行顺序可能与函数的添加顺序不相同 CharacterDelegateMulticast2.Clear(); // 绑定实例个数为:0 // Add Lambda auto LambdaDelegateMCProc = [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("LambdaDelegateMCProc : %d"), nCode); }; CharacterDelegateMulticast3.AddLambda(LambdaDelegateMCProc);// 绑定实例个数为:1 CharacterDelegateMulticast3.AddLambda( [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("LambdaDelegateMCProc2 : %d"), nCode); } );// 绑定实例个数为:2 CharacterDelegateMulticast3.Broadcast(102);// 执行绑定实例列表(共2个) 注:执行顺序可能与函数的添加顺序不相同 // Add Weak Lambda auto WeakLambdaDelegateMCProc = [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateMCProc : %d"), nCode); }; UDelegatepTestClass* UObjMC1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegateMulticast4.AddWeakLambda(UObjMC1, WeakLambdaDelegateMCProc);// 绑定实例个数为:1 UDelegatepTestClass* UObjMC2 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegateMulticast4.AddWeakLambda( UObjMC2, [](int nCode)->void { UE_LOG(LogTemp, Log, TEXT("WeakLambdaDelegateMCProc2 : %d"), nCode); } );// 绑定实例个数为:2 CharacterDelegateMulticast4.Broadcast(103);// 执行绑定实例列表(共2个) 注:执行顺序可能与函数的添加顺序不相同 // Add SP(Shared Pointer) TSharedRef<DelegateCppTestClass> ObjMCSP1 = MakeShareable(new DelegateCppTestClass()); CharacterDelegateMulticast5.AddSP(ObjMCSP1, &DelegateCppTestClass::CppDelegateProc2);// 绑定实例个数为:1 TSharedRef<DelegateCppTestClass> ObjMCSP2 = MakeShared<DelegateCppTestClass>(); CharacterDelegateMulticast5.AddSP(ObjMCSP2, &DelegateCppTestClass::CppDelegateProc3);// 绑定实例个数为:2 CharacterDelegateMulticast5.Broadcast(104); // Add Thread Safe SP(Shared Pointer) 注:指定了ESPMode::ThreadSafe,会对SharedReferenceCount、WeakReferenceCount引用计数的进行原子操作,保证线程安全 TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeMCSP1 = MakeShareable(new DelegateCppTestClass()); CharacterDelegateMulticast6.AddThreadSafeSP(ObjSafeMCSP1, &DelegateCppTestClass::CppDelegateProc4);// 绑定实例个数为:1 TSharedRef<DelegateCppTestClass, ESPMode::ThreadSafe> ObjSafeMCSP2 = MakeShared<DelegateCppTestClass, ESPMode::ThreadSafe>(); CharacterDelegateMulticast6.AddThreadSafeSP(ObjSafeMCSP2, &DelegateCppTestClass::CppDelegateProc5);// 绑定实例个数为:2 CharacterDelegateMulticast6.Broadcast(105);// 执行绑定实例列表(共2个) 注:执行顺序可能与函数的添加顺序不相同 // Add UObject UDelegatepTestClass* UObjMC3 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegateMulticast7.AddUObject(UObjMC3, &UDelegatepTestClass::DelegateProc1);// 绑定实例个数为:1 CharacterDelegateMulticast7.AddUObject(UObjMC3, &UDelegatepTestClass::DelegateProc2);// 绑定实例个数为:2 CharacterDelegateMulticast7.Broadcast(106);// 执行绑定实例列表(共2个) 注:执行顺序可能与函数的添加顺序不相同 // Add UFunction UDelegatepTestClass* UObjMC4 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegateMulticast8.AddUFunction(UObjMC4, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));// 绑定实例个数为:1 CharacterDelegateMulticast8.Broadcast(107);// 执行绑定实例列表(共1个) 注:执行顺序可能与函数的添加顺序不相同 }
注1:AddRaw函数用于绑定普通c++对象的成员函数,若该c++对象已被销毁,触发代理执行该对象的成员函数,将会导致内存违规操作
注2:AddLambda函数用于绑定lambda表达式,若lambda表达式捕获外部变量已被销毁,触发代理执行lambda表达式,将会导致内存违规操作
注3:AddWeakLambda、AddUObject、AddUFunction绑定时会与一个UObject对象进行弱引用关联(不影响该对象被gc回收),在触发代理时,会先检查该UObject的有效性,再来执行代理
注4:BindSP、BindThreadSafeSP绑定时会与一个智能指针对象进行弱引用关联(不影响该对象的内存回收),在触发代理时,会先检查该智能指针对象的有效性,再来执行代理
注5:可通过Remove删除指定Handle的代理对象;通过RemoveAll删除相关UObject对象所有的代理对象;通过Clear清除代理对象列表
事件
1. 定义返回值为void含1个int类型参数的事件类型FCharacterEvent
DECLARE_EVENT_OneParam(ATPSProjectCharacter, FCharacterEvent, int); // TBaseMulticastDelegate<void, int>
注1:定义事件类型宏的第一个参数为拥有该事件类型A的类型B,即为类型B为事件类型A的友元类,可以访问A中的私有成员
注2:定义事件类型宏一般放在一个类的内部(即访问该类型时需要带上所在类的名称前缀,如ATPSProjectCharacter::FCharacterEvent),可有效减少事件类型名称冲突
2. 声明代理对象
FCharacterEvent CharacterEvent;
事件本质是一个多播代理,另外,在事件的友元类型ATPSProjectCharacter中,可访问事件的私有成员
动态代理
1. 定义返回值为void含1个int类型参数的动态代理类型FCharacterDelegate_Dynamic
DECLARE_DYNAMIC_DELEGATE_OneParam(FCharacterDelegate_Dynamic, int, nCode); // TBaseDynamicDelegate<FWeakObjectPtr, void, int>
2. 定义返回值为bool含1个int类型参数的动态代理类型FCharacterDelegate_DynamicRetVal
DECLARE_DYNAMIC_DELEGATE_RetVal_OneParam(bool, FCharacterDelegate_DynamicRetVal, int, nCode); // TBaseDynamicDelegate<FWeakObjectPtr, bool, int>
以FCharacterDelegate_Dynamic为例,讲述动态代理的绑定、触发执行及存在的风险
void ATPSProjectCharacter::OnDelegateDynamicTest() { bool bd1 = CharacterDelegateDynamic.IsBound(); // false UDelegatepTestClass* UObjDy1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); CharacterDelegateDynamic.BindUFunction(UObjDy1, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));// 绑定实例个数为:1 bool bd2 = CharacterDelegateDynamic.IsBound(); // true CharacterDelegateDynamic.ExecuteIfBound(200); CharacterDelegateDynamic.Unbind(); // 使用BindDynamic宏 CharacterDelegateDynamic2.BindDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc); if (CharacterDelegateDynamic2.IsBound()) // true { CharacterDelegateDynamic2.Execute(201); } CharacterDelegateDynamic2.Clear(); // 功能与Unbind一样,内部是直接调用Unbind方法 }
注:BindUFunction绑定时会与一个UObject对象进行弱引用关联(不影响该对象被gc回收)
若UObject对象被gc回收,直接调用Execute触发代理,将会导致内存违规操作;可先调用IsBound或调用ExecuteIfBound触发代理来检查该UObject的有效性,再来执行代理
动态多播代理
定义返回值为void含1个int类型参数的动态多播代理类型FCharacterDelegate_DynamicMulticast
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FCharacterDelegate_DynamicMulticast, int, nCode); // TBaseDynamicMulticastDelegate<FWeakObjectPtr, void, int>
FCharacterDelegate_DynamicMulticast为例,讲述动态多播代理的绑定、触发执行及存在的风险
void ATPSProjectCharacter::OnDelegateDynamicMulticastTest() { UDelegatepTestClass* UObjDMC1 = NewObject<UDelegatepTestClass>(this, UDelegatepTestClass::StaticClass()); // 使用AddDynamic宏 //CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateProc1); // 运行时错误:Unable to bind delegate (function might not be marked as a UFUNCTION or object may be pending kill) CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateUFunctionProc1); // 绑定实例个数为:1 //CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateUFunctionProc1); // 运行时错误 加入DelegateUFunctionProc1的绑定实例已存在 CharacterDelegateDynamicMulticast.AddDynamic(UObjDMC1, &UDelegatepTestClass::DelegateUFunctionProc2); // 绑定实例个数为:2 // 使用AddUniqueDynamic宏 CharacterDelegateDynamicMulticast.AddUniqueDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc); // 绑定实例个数为:3 CharacterDelegateDynamicMulticast.AddUniqueDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc); // 加入DynamicMulticastProc的绑定实例已存在 CharacterDelegateDynamicMulticast.AddUniqueDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc2); // 绑定实例个数为:4 FScriptDelegate delegateVar1; // FScriptDelegate即为TScriptDelegate<> delegateVar1.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ATPSProjectCharacter::DynamicMulticastProc3"))); CharacterDelegateDynamicMulticast.Add(delegateVar1); // 绑定实例个数为:5 FScriptDelegate delegateVar2; delegateVar2.BindUFunction(this, STATIC_FUNCTION_FNAME(TEXT("ATPSProjectCharacter::DynamicMulticastProc3"))); //CharacterDelegateDynamicMulticast.Add(delegateVar2); // 运行时错误 加入DynamicMulticastProc3的绑定实例已存在 CharacterDelegateDynamicMulticast.AddUnique(delegateVar2); // 加入DynamicMulticastProc3的绑定实例已存在 // 使用RemoveDynamic宏 CharacterDelegateDynamicMulticast.RemoveDynamic(this, &ATPSProjectCharacter::DynamicMulticastProc2); // 绑定实例个数为:4 // 使用IsAlreadyBound宏 bool bDMC1 = CharacterDelegateDynamicMulticast.IsAlreadyBound(this, &ATPSProjectCharacter::DynamicMulticastProc3);// true CharacterDelegateDynamicMulticast.Remove(delegateVar2); // 绑定实例个数为:3 CharacterDelegateDynamicMulticast.Remove(UObjDMC1, STATIC_FUNCTION_FNAME(TEXT("UDelegatepTestClass::DelegateUFunctionProc1")));// 绑定实例个数为:2 bool bDMC2 = CharacterDelegateDynamicMulticast.IsAlreadyBound(this, &ATPSProjectCharacter::DynamicMulticastProc3); // false CharacterDelegateDynamicMulticast.RemoveAll(this); // 绑定实例个数为:1 CharacterDelegateDynamicMulticast.Broadcast(300); // 执行绑定实例列表(共1个) 注:执行顺序可能与函数的添加顺序不相同 CharacterDelegateDynamicMulticast.Clear(); // 清除所有绑定实例 }
需要注意的是,只有动态多播代理才能在蓝图中使用(对其进行绑定、解绑、Broadcast、以及清除操作)
BP_MyTPSProjectCharacter是一个放置在关卡中的派生于ATPSProjectCharacter的蓝图对象
下图为在关卡蓝图中分配并绑定事件到BP_MyTPSProjectCharacter实例的CharacterDelegateDynamicMulticast动态多播代理变量上,按下8按键触发代理执行
引擎内建委托
系统和引擎
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Runtime\Core\Public\Misc\CoreDelegates.h **/ class CORE_API FCoreDelegates { // Callback for platform handling when flushing async loads. DECLARE_MULTICAST_DELEGATE(FOnAsyncLoadingFlush); static FOnAsyncLoadingFlush OnAsyncLoadingFlush; // Callback for a game thread interruption point when a async load flushing. Used to updating UI during long loads. DECLARE_MULTICAST_DELEGATE(FOnAsyncLoadingFlushUpdate); static FOnAsyncLoadingFlushUpdate OnAsyncLoadingFlushUpdate; // Callback on the game thread when an async load is started. This goes off before the packages has finished loading DECLARE_MULTICAST_DELEGATE_OneParam(FOnAsyncLoadPackage, const FString&); static FOnAsyncLoadPackage OnAsyncLoadPackage; DECLARE_MULTICAST_DELEGATE_OneParam(FOnSyncLoadPackage, const FString&); static FOnSyncLoadPackage OnSyncLoadPackage; // Callback when an ensure has occurred static FOnHandleSystemEnsure OnHandleSystemEnsure; // Callback when an error (crash) has occurred static FOnHandleSystemError OnHandleSystemError; // Called when an error occurred. static FSimpleMulticastDelegate OnShutdownAfterError; // Called when appInit is called, very early in startup static FSimpleMulticastDelegate OnInit; // Called at the end of UEngine::Init, right before loading PostEngineInit modules for both normal execution and commandlets static FSimpleMulticastDelegate OnPostEngineInit; // Called at the very end of engine initialization, right before the engine starts ticking. This is not called for commandlets static FSimpleMulticastDelegate OnFEngineLoopInitComplete; // Called when the application is about to exit. static FSimpleMulticastDelegate OnExit; // Called when before the application is exiting. static FSimpleMulticastDelegate OnPreExit; // Called at the beginning of a frame static FSimpleMulticastDelegate OnBeginFrame; // Called at the end of a frame static FSimpleMulticastDelegate OnEndFrame; // Called at the beginning of a frame on the renderthread static FSimpleMulticastDelegate OnBeginFrameRT; // Called at the end of a frame on the renderthread static FSimpleMulticastDelegate OnEndFrameRT; // IOS-style temperature updates, allowing game to scale down to let temp drop (to avoid thermal throttling on mobile, for instance) */ // There is a parellel enum in ApplicationLifecycleComponent enum class ETemperatureSeverity : uint8 { Unknown, Good, Bad, Serious, Critical, NumSeverities, }; DECLARE_MULTICAST_DELEGATE_OneParam(FOnTemperatureChange, ETemperatureSeverity); static FOnTemperatureChange OnTemperatureChange; /** Called when the OS goes into low power mode */ DECLARE_MULTICAST_DELEGATE_OneParam(FOnLowPowerMode, bool); static FOnLowPowerMode OnLowPowerMode; DECLARE_MULTICAST_DELEGATE_TwoParams(FOnSystemResolutionChanged, uint32 /*ResX*/, uint32 /*ResY*/); static FOnSystemResolutionChanged OnSystemResolutionChanged; /** IOS-style application lifecycle delegates */ DECLARE_MULTICAST_DELEGATE(FApplicationLifetimeDelegate); // This is called when the application is about to be deactivated (e.g., due to a phone call or SMS or the sleep button). // The game should be paused if possible, etc... static FApplicationLifetimeDelegate ApplicationWillDeactivateDelegate; // Called when the application has been reactivated (reverse any processing done in the Deactivate delegate) static FApplicationLifetimeDelegate ApplicationHasReactivatedDelegate; // This is called when the application is being backgrounded (e.g., due to switching // to another app or closing it via the home button) // The game should release shared resources, save state, etc..., since it can be // terminated from the background state without any further warning. static FApplicationLifetimeDelegate ApplicationWillEnterBackgroundDelegate; // for instance, hitting the home button // Called when the application is returning to the foreground (reverse any processing done in the EnterBackground delegate) static FApplicationLifetimeDelegate ApplicationHasEnteredForegroundDelegate; // This *may* be called when the application is getting terminated by the OS. // There is no guarantee that this will ever be called on a mobile device, // save state when ApplicationWillEnterBackgroundDelegate is called instead. static FApplicationLifetimeDelegate ApplicationWillTerminateDelegate; // Called when the OS needs control of the music (parameter is true) or when the OS returns // control of the music to the application (parameter is false). This can happen due to a // phone call or timer or other OS-level event. This is currently triggered only on iOS // devices. DECLARE_MULTICAST_DELEGATE_OneParam(FUserMusicInterruptDelegate, bool); static FUserMusicInterruptDelegate UserMusicInterruptDelegate; // [iOS only] Called when the mute switch is detected as changed or when the // volume changes. Parameter 1 is the mute switch state (true is muted, false is // unmuted). Parameter 2 is the volume as an integer from 0 to 100. DECLARE_MULTICAST_DELEGATE_TwoParams(FAudioMuteDelegate, bool, int); static FAudioMuteDelegate AudioMuteDelegate; // [iOS only] Called when the audio device changes // For instance, when the headphones are plugged in or removed DECLARE_MULTICAST_DELEGATE_OneParam(FAudioRouteChangedDelegate, bool); static FAudioRouteChangedDelegate AudioRouteChangedDelegate; // Called when the OS is running low on resources and asks the application to free up any cached resources, drop graphics quality etc. static FApplicationLifetimeDelegate ApplicationShouldUnloadResourcesDelegate; /** Sent when a device screen orientation changes */ DECLARE_MULTICAST_DELEGATE_OneParam(FApplicationReceivedOnScreenOrientationChangedNotificationDelegate, int32); static FApplicationReceivedOnScreenOrientationChangedNotificationDelegate ApplicationReceivedScreenOrientationChangedNotificationDelegate; /** Callback for notifications regarding changes of the rendering thread. */ DECLARE_MULTICAST_DELEGATE(FRenderingThreadChanged) /** Sent just after the rendering thread has been created. */ static FRenderingThreadChanged PostRenderingThreadCreated; /* Sent just before the rendering thread is destroyed. */ static FRenderingThreadChanged PreRenderingThreadDestroyed; // Called to request that systems free whatever memory they are able to. Called early in LoadMap. // Caller is responsible for flushing rendering etc. See UEngine::TrimMemory static FSimpleMulticastDelegate& GetMemoryTrimDelegate(); // Called when OOM event occurs, after backup memory has been freed, so there's some hope of being effective static FSimpleMulticastDelegate& GetOutOfMemoryDelegate(); }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectGlobals.h **/ struct COREUOBJECT_API FCoreUObjectDelegates { /** Sent at the very beginning of LoadMap */ DECLARE_MULTICAST_DELEGATE_OneParam(FPreLoadMapDelegate, const FString& /* MapName */); static FPreLoadMapDelegate PreLoadMap; /** Sent at the _successful_ end of LoadMap */ DECLARE_MULTICAST_DELEGATE_OneParam(FPostLoadMapDelegate, UWorld* /* LoadedWorld */); static FPostLoadMapDelegate PostLoadMapWithWorld; /** Sent when a network replay has started */ static FSimpleMulticastDelegate PostDemoPlay; /** Called before garbage collection */ static FSimpleMulticastDelegate& GetPreGarbageCollectDelegate(); /** Delegate type for reachability analysis external roots callback. First parameter is FGarbageCollectionTracer to use for tracing, second is flags with which objects should be kept alive regardless, third is whether to force single threading */ DECLARE_MULTICAST_DELEGATE_ThreeParams(FTraceExternalRootsForReachabilityAnalysisDelegate, FGarbageCollectionTracer&, EObjectFlags, bool); /** Called as last phase of reachability analysis. Allow external systems to add UObject roots *after* first reachability pass has been done */ static FTraceExternalRootsForReachabilityAnalysisDelegate TraceExternalRootsForReachabilityAnalysis; /** Called after reachability analysis, before any purging */ static FSimpleMulticastDelegate PostReachabilityAnalysis; /** Called after garbage collection */ static FSimpleMulticastDelegate& GetPostGarbageCollect(); /** Called before ConditionalBeginDestroy phase of garbage collection */ static FSimpleMulticastDelegate PreGarbageCollectConditionalBeginDestroy; /** Called after ConditionalBeginDestroy phase of garbage collection */ static FSimpleMulticastDelegate PostGarbageCollectConditionalBeginDestroy; /** Queries whether an object should be loaded on top ( replace ) an already existing one */ DECLARE_DELEGATE_RetVal_OneParam(bool, FOnLoadObjectsOnTop, const FString&); static FOnLoadObjectsOnTop ShouldLoadOnTop; /** Called when path to world root is changed */ DECLARE_MULTICAST_DELEGATE_OneParam(FPackageCreatedForLoad, class UPackage*); static FPackageCreatedForLoad PackageCreatedForLoad; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Runtime\Engine\Classes\Engine\Engine.h **/ class ENGINE_API UEngine : public UObject , public FExec { /** Delegate called just prior to rendering. */ FPreRenderDelegate PreRenderDelegate; FPreRenderDelegate& GetPreRenderDelegate() { return PreRenderDelegate; } /** * Error message event relating to server travel failures * * @param Type type of travel failure * @param ErrorString additional error message */ DECLARE_EVENT_ThreeParams(UEngine, FOnTravelFailure, UWorld*, ETravelFailure::Type, const FString&); FOnTravelFailure TravelFailureEvent; /** * Error message event relating to network failures * * @param Type type of network failure * @param Name name of netdriver that generated the failure * @param ErrorString additional error message */ DECLARE_EVENT_FourParams(UEngine, FOnNetworkFailure, UWorld*, UNetDriver*, ENetworkFailure::Type, const FString&); FOnNetworkFailure NetworkFailureEvent; /** * Network lag detected. For the server this means all clients are timing out. On the client it means you are timing out. */ DECLARE_EVENT_ThreeParams(UEngine, FOnNetworkLagStateChanged, UWorld*, UNetDriver*, ENetworkLagState::Type); FOnNetworkLagStateChanged NetworkLagStateChangedEvent; /** Triggered when a world is added. */ DECLARE_EVENT_OneParam( UEngine, FWorldAddedEvent , UWorld* ); /** Return the world added event. */ FWorldAddedEvent& OnWorldAdded() { return WorldAddedEvent; } /** Triggered when a world is destroyed. */ DECLARE_EVENT_OneParam( UEngine, FWorldDestroyedEvent , UWorld* ); /** Return the world destroyed event. */ FWorldDestroyedEvent& OnWorldDestroyed() { return WorldDestroyedEvent; } };
编辑器
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Editor\UnrealEd\Public\Editor.h **/ #if WITH_EDITOR struct UNREALED_API FEditorDelegates { /** Sent when a PIE session is beginning (before we decide if PIE can run - allows clients to avoid blocking PIE) */ static FOnPIEEvent PreBeginPIE; /** Sent when a PIE session is beginning (but hasn't actually started yet) */ static FOnPIEEvent BeginPIE; /** Sent when a PIE session has fully started and after BeginPlay() has been called */ static FOnPIEEvent PostPIEStarted; /** Sent when a PIE session is ending, before anything else happens */ static FOnPIEEvent PrePIEEnded; /** Sent when a PIE session is ending */ static FOnPIEEvent EndPIE; /** Called when a map is opened, giving map name, and whether it was a template */ static FOnMapOpened OnMapOpened; }; #endif
游戏世界
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Runtime\Engine\Classes\Engine\World.h **/ class ENGINE_API FWorldDelegates { DECLARE_MULTICAST_DELEGATE_TwoParams(FOnWorldTickStart, ELevelTick, float); static FOnWorldTickStart OnWorldTickStart; // Delegate called before actors are ticked for each world. Delta seconds is already dilated and clamped. DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnWorldPreActorTick, UWorld* /*World*/, ELevelTick/**Tick Type*/, float/**Delta Seconds*/); static FOnWorldPreActorTick OnWorldPreActorTick; DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnWorldPostActorTick, UWorld* /*World*/, ELevelTick/**Tick Type*/, float/**Delta Seconds*/); static FOnWorldPostActorTick OnWorldPostActorTick; // Callback for world creation static FWorldEvent OnPostWorldCreation; // Callback for world initialization (pre) static FWorldInitializationEvent OnPreWorldInitialization; // Callback for world initialization (post) static FWorldInitializationEvent OnPostWorldInitialization; // Callback for world cleanup start static FWorldCleanupEvent OnWorldCleanup; // Callback for world cleanup end static FWorldCleanupEvent OnPostWorldCleanup; // Callback for world destruction (only called for initialized worlds) static FWorldEvent OnPreWorldFinishDestroy; // Sent when a ULevel is added to the world via UWorld::AddToWorld static FOnLevelChanged LevelAddedToWorld; // Sent when a ULevel is removed from the world via UWorld::RemoveFromWorld or // LoadMap (a NULL object means the LoadMap case, because all levels will be // removed from the world without a RemoveFromWorld call for each) static FOnLevelChanged LevelRemovedFromWorld; // Global Callback after actors have been initialized (on any world) static UWorld::FOnWorldInitializedActors OnWorldInitializedActors; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Runtime\Engine\Classes\Engine\World.h **/ DECLARE_MULTICAST_DELEGATE_OneParam(FOnActorSpawned, AActor*); class ENGINE_API UWorld final : public UObject, public FNetworkNotify { /** a delegate that broadcasts a notification whenever an actor is spawned */ FOnActorSpawned OnActorSpawned; /** Add a listener for OnActorSpawned events */ FDelegateHandle AddOnActorSpawnedHandler( const FOnActorSpawned::FDelegate& InHandler ); /** Remove a listener for OnActorSpawned events */ void RemoveOnActorSpawnedHandler( FDelegateHandle InHandle ); DECLARE_MULTICAST_DELEGATE_OneParam(FOnWorldInitializedActors, const FActorsInitializedParams&); FOnWorldInitializedActors OnActorsInitialized; DECLARE_EVENT_OneParam(UWorld, FOnNetTickEvent, float); DECLARE_EVENT(UWorld, FOnTickFlushEvent); /** Event to gather up all net drivers and call TickDispatch at once */ FOnNetTickEvent TickDispatchEvent; /** Event to gather up all net drivers and call PostTickDispatch at once */ FOnTickFlushEvent PostTickDispatchEvent; /** Event to gather up all net drivers and call TickFlush at once */ FOnNetTickEvent TickFlushEvent; /** Event to gather up all net drivers and call PostTickFlush at once */ FOnTickFlushEvent PostTickFlushEvent; /** Called when the number of levels changes. */ DECLARE_EVENT(UWorld, FOnLevelsChangedEvent); /** Broadcasts whenever the number of levels changes */ FOnLevelsChangedEvent LevelsChangedEvent; DECLARE_EVENT_OneParam(UWorld, FOnGameStateSetEvent, AGameStateBase*); /** Called whenever the gamestate is set on the world. */ FOnGameStateSetEvent GameStateSetEvent; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* Engine\Source\Runtime\Engine\Public\GameDelegates.h */ class ENGINE_API FGameDelegates { /** Return a single FGameDelegates object */ static FGameDelegates& Get(); // Called when an exit command is received DEFINE_GAME_DELEGATE_TYPED(ExitCommandDelegate, FSimpleMulticastDelegate); // Called when ending playing a map DEFINE_GAME_DELEGATE_TYPED(EndPlayMapDelegate, FSimpleMulticastDelegate); // Called when a matinee is canceled DEFINE_GAME_DELEGATE_TYPED(MatineeCancelledDelegate, FSimpleMulticastDelegate); // Called when a pending connection has been lost DEFINE_GAME_DELEGATE_TYPED(PendingConnectionLostDelegate, FPendingConnectionLostDelegate); // Called when a player is disconnecting due to network failure DEFINE_GAME_DELEGATE(HandleDisconnectDelegate); };
引擎子系统
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API FNetDelegates { /** * Delegate fired when a pending net game has created a UNetConnection to the server but hasn't sent the initial join message yet. * * @param PendingNetGame pointer to the PendingNetGame that is initializing its connection to a server. */ DECLARE_MULTICAST_DELEGATE_OneParam(FOnPendingNetGameConnectionCreated, UPendingNetGame* /*PendingNetGame*/); static FOnPendingNetGameConnectionCreated OnPendingNetGameConnectionCreated; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_VTABLE UNetDriver : public UObject, public FExec { #if !UE_BUILD_SHIPPING /** Delegate for hooking ProcessRemoteFunction */ FOnSendRPC SendRPCDel; #endif }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_VTABLE UNetConnection : public UPlayer { #if !UE_BUILD_SHIPPING /** Delegate for hooking ReceivedRawPacket */ FOnReceivedRawPacket ReceivedRawPacketDel; /** Delegate for hooking LowLevelSend */ FOnLowLevelSend LowLevelSendDel; #endif }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API ULevelStreaming : public UObject { /** Called when level is streamed in */ UPROPERTY(BlueprintAssignable) FLevelStreamingLoadedStatus OnLevelLoaded; /** Called when level is streamed out */ UPROPERTY(BlueprintAssignable) FLevelStreamingLoadedStatus OnLevelUnloaded; /** Called when level is added to the world */ UPROPERTY(BlueprintAssignable) FLevelStreamingVisibilityStatus OnLevelShown; /** Called when level is removed from the world */ UPROPERTY(BlueprintAssignable) FLevelStreamingVisibilityStatus OnLevelHidden; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API FPhysicsDelegates { DECLARE_MULTICAST_DELEGATE_OneParam(FOnPhysSceneInit, FPhysScene*); static FOnPhysSceneInit OnPhysSceneInit; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class FPhysScene_PhysX { DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPhysScenePreTick, FPhysScene_PhysX*, float /*DeltaSeconds*/); FOnPhysScenePreTick OnPhysScenePreTick; DECLARE_MULTICAST_DELEGATE_TwoParams(FOnPhysSceneStep, FPhysScene_PhysX*, float /*DeltaSeconds*/); FOnPhysSceneStep OnPhysSceneStep; DECLARE_MULTICAST_DELEGATE_OneParam(FOnPhysScenePostTick, FPhysScene*); FOnPhysScenePostTick OnPhysScenePostTick; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class CORE_API FModuleManager : private FSelfRegisteringExec { /** * Gets an event delegate that is executed when the set of known modules changed, i.e. upon module load or unload. * * The first parameter is the name of the module that changed. * The second parameter is the reason for the change. * * @return The event delegate. */ DECLARE_EVENT_TwoParams(FModuleManager, FModulesChangedEvent, FName, EModuleChangeReason); FModulesChangedEvent& OnModulesChanged( ) { return ModulesChangedEvent; } /** * Gets a multicast delegate that is executed when any UObjects need processing after a module was loaded. * * @return The delegate. */ DECLARE_EVENT_TwoParams(FModuleManager, ProcessLoadedObjectsEvent, FName, bool); ProcessLoadedObjectsEvent& OnProcessLoadedObjectsCallback() { return ProcessLoadedObjectsCallback; } /** * Gets a delegate that is executed when a module containing UObjects has been loaded. * * The first parameter is the name of the loaded module. * * @return The event delegate. */ DECLARE_DELEGATE_RetVal_OneParam(bool, FIsPackageLoadedCallback, FName); FIsPackageLoadedCallback& IsPackageLoadedCallback() { return IsPackageLoaded; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class IGameMoviePlayer { /** Called before playing a movie if the loading screen has not been prepared. */ DECLARE_EVENT(IGameMoviePlayer, FOnPrepareLoadingScreen) virtual FOnPrepareLoadingScreen& OnPrepareLoadingScreen() = 0; /* Callback for when the LoadingScreen setup above in WidgetLoadingScreen is displayed **/ DECLARE_EVENT(IGameMoviePlayer, FOnMoviePlaybackStarted) virtual FOnMoviePlaybackStarted& OnMoviePlaybackStarted() = 0; DECLARE_EVENT(IGameMoviePlayer, FOnMoviePlaybackFinished) virtual FOnMoviePlaybackFinished& OnMoviePlaybackFinished() = 0; DECLARE_EVENT_OneParam(IGameMoviePlayer, FOnMovieClipFinished, const FString&) virtual FOnMovieClipFinished& OnMovieClipFinished() = 0; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ONLINESUBSYSTEM_API FOnlineSubsystemDelegates { public: /** * Notification that a new online subsystem instance has been created * * @param NewSubsystem the new instance created */ DECLARE_MULTICAST_DELEGATE_OneParam(FOnOnlineSubsystemCreated, class IOnlineSubsystem* /*NewSubsystem*/); static FOnOnlineSubsystemCreated OnOnlineSubsystemCreated; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class GenericApplication { DECLARE_EVENT_OneParam(GenericApplication, FOnDisplayMetricsChanged, const FDisplayMetrics&); /** Notifies subscribers when any of the display metrics change: e.g. resolution changes or monitor sare re-arranged. */ FOnDisplayMetricsChanged& OnDisplayMetricsChanged(){ return OnDisplayMetricsChangedEvent; } /** Delegate for virtual keyboard being shown/hidden in case UI wants to slide out of the way */ DECLARE_EVENT_OneParam(FSlateApplication, FVirtualKeyboardShownEvent, FPlatformRect); FVirtualKeyboardShownEvent& OnVirtualKeyboardShown() { return VirtualKeyboardShownEvent; } DECLARE_EVENT(FSlateApplication, FVirtualKeyboardHiddenEvent); FVirtualKeyboardHiddenEvent& OnVirtualKeyboardHidden() { return VirtualKeyboardHiddenEvent; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class SLATE_API FSlateApplication { static FSlateApplication& Get() { check( IsInGameThread() || IsInSlateThread() || IsInAsyncLoadingThread() ); return *CurrentApplication; } /** Event before slate application ticks. */ DECLARE_EVENT_OneParam(FSlateApplication, FSlateTickEvent, float); FSlateTickEvent& OnPreTick() { return PreTickEvent; } /** Event after slate application ticks. */ FSlateTickEvent& OnPostTick() { return PostTickEvent; } /** Delegate called when a window is about to be destroyed */ DECLARE_EVENT_OneParam(FSlateApplication, FOnWindowBeingDestroyed, const SWindow&); FOnWindowBeingDestroyed& OnWindowBeingDestroyed() { return WindowBeingDestroyedEvent; } /** Sets the handler for otherwise unhandled key down events. This is used by the editor to provide a global action list, if the key was not consumed by any widget. */ void SetUnhandledKeyDownEventHandler( const FOnKeyEvent& NewHandler ); /** Delegate for when a key down event occurred but was not handled in any other way by ProcessKeyDownMessage */ FOnKeyEvent UnhandledKeyDownEventHandler; DECLARE_EVENT_OneParam(FSlateApplication, FApplicationActivationStateChangedEvent, const bool /*IsActive*/) virtual FApplicationActivationStateChangedEvent& OnApplicationActivationStateChanged() { return ApplicationActivationStateChangedEvent; } FApplicationActivationStateChangedEvent ApplicationActivationStateChangedEvent; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API UGameViewportClient : public UScriptViewportClient, public FExec { #if WITH_EDITOR /** Delegate called when game viewport client received input key */ FOnGameViewportInputKey GameViewportInputKeyDelegate; #endif /** Delegate called at the end of the frame when a screenshot is captured */ static FOnScreenshotCaptured ScreenshotCapturedDelegate; /** Delegate called right after the viewport is rendered */ static FOnViewportRendered ViewportRenderedDelegate; /** Delegate called when a request to close the viewport is received */ FOnCloseRequested CloseRequestedDelegate; /** Delegate called when the window owning the viewport is requested to close */ FOnWindowCloseRequested WindowCloseRequestedDelegate; /** Delegate called when the game viewport is created. */ static FSimpleMulticastDelegate CreatedDelegate; /** Delegate called when a player is added to the game viewport */ FOnGameViewportClientPlayerAction PlayerAddedDelegate; /** Delegate called when a player is removed from the game viewport */ FOnGameViewportClientPlayerAction PlayerRemovedDelegate; /** Delegate called when the engine starts drawing a game viewport */ FSimpleMulticastDelegate BeginDrawDelegate; /** Delegate called when the game viewport is drawn, before drawing the console */ FSimpleMulticastDelegate DrawnDelegate; /** Delegate called when the engine finishes drawing a game viewport */ FSimpleMulticastDelegate EndDrawDelegate; /** Delegate called when ticking the game viewport */ FOnGameViewportTick TickDelegate; /** Delegate called when the engine toggles fullscreen */ FOnToggleFullscreen ToggleFullscreenDelegate; };
GamePlay框架
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API FGameModeEvents { public: /** * GameMode initialization has occurred * - Called at the end of AGameModeBase::InitGame * - AGameSession has also been initialized * - Possible some child level initialization hasn't finished * * @param GameMode the game mode actor that has been initialized */ DECLARE_EVENT_OneParam(AGameModeBase, FGameModeInitializedEvent, AGameModeBase* /*GameMode*/); /** * Client pre login event, triggered when a client first contacts a server * * @param GameMode the game mode actor that has been initialized * @param NewPlayer the unique id of the player attempting to join * @param ErrorMessage current state of any error messages, setting this value non empty will reject the player */ DECLARE_EVENT_ThreeParams(AGameModeBase, FGameModePreLoginEvent, AGameModeBase* /*GameMode*/, const FUniqueNetIdRepl& /*NewPlayer*/, FString& /*ErrorMessage*/); /** * Post login event, triggered when a player joins the game as well as after non-seamless ServerTravel * * This is called after the player has finished initialization */ DECLARE_EVENT_TwoParams(AGameModeBase, FGameModePostLoginEvent, AGameModeBase* /*GameMode*/, APlayerController* /*NewPlayer*/); /** * Logout event, triggered when a player leaves the game as well as during non-seamless ServerTravel * * Note that this is called before performing any cleanup of the specified AController */ DECLARE_EVENT_TwoParams(AGameModeBase, FGameModeLogoutEvent, AGameModeBase* /*GameMode*/, AController* /*Exiting*/); /** * Match state has changed via SetMatchState() * * @param MatchState new match state */ DECLARE_EVENT_OneParam(AGameModeBase, FGameModeMatchStateSetEvent, FName /*MatchState*/); public: static FGameModeInitializedEvent& OnGameModeInitializedEvent() { return GameModeInitializedEvent; } static FGameModePreLoginEvent& OnGameModePreLoginEvent() { return GameModePreLoginEvent; } static FGameModePostLoginEvent& OnGameModePostLoginEvent() { return GameModePostLoginEvent; } static FGameModeLogoutEvent& OnGameModeLogoutEvent() { return GameModeLogoutEvent; } static FGameModeMatchStateSetEvent& OnGameModeMatchStateSetEvent() { return GameModeMatchStateSetEvent; } static FGameModeInitializedEvent GameModeInitializedEvent; static FGameModePreLoginEvent GameModePreLoginEvent; static FGameModePostLoginEvent GameModePostLoginEvent; static FGameModeLogoutEvent GameModeLogoutEvent; static FGameModeMatchStateSetEvent GameModeMatchStateSetEvent; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API AActor : public UObject { //~============================================================================================== // Delegates /** Called when the actor is damaged in any way. */ UPROPERTY(BlueprintAssignable, Category="Game|Damage") FTakeAnyDamageSignature OnTakeAnyDamage; /** Called when the actor is damaged by point damage. */ UPROPERTY(BlueprintAssignable, Category="Game|Damage") FTakePointDamageSignature OnTakePointDamage; /** Called when the actor is damaged by radial damage. */ UPROPERTY(BlueprintAssignable, Category="Game|Damage") FTakeRadialDamageSignature OnTakeRadialDamage; /** * Called when another actor begins to overlap this actor, for example a player walking into a trigger. * For events when objects have a blocking collision, for example a player hitting a wall, see 'Hit' events. * @note Components on both this and the other Actor must have bGenerateOverlapEvents set to true to generate overlap events. */ UPROPERTY(BlueprintAssignable, Category="Collision") FActorBeginOverlapSignature OnActorBeginOverlap; /** * Called when another actor stops overlapping this actor. * @note Components on both this and the other Actor must have bGenerateOverlapEvents set to true to generate overlap events. */ UPROPERTY(BlueprintAssignable, Category="Collision") FActorEndOverlapSignature OnActorEndOverlap; /** Called when the mouse cursor is moved over this actor if mouse over events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input") FActorBeginCursorOverSignature OnBeginCursorOver; /** Called when the mouse cursor is moved off this actor if mouse over events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input") FActorEndCursorOverSignature OnEndCursorOver; /** Called when the left mouse button is clicked while the mouse is over this actor and click events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input") FActorOnClickedSignature OnClicked; /** Called when the left mouse button is released while the mouse is over this actor and click events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Mouse Input") FActorOnReleasedSignature OnReleased; /** Called when a touch input is received over this actor when touch events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Touch Input") FActorOnInputTouchBeginSignature OnInputTouchBegin; /** Called when a touch input is received over this component when touch events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Touch Input") FActorOnInputTouchEndSignature OnInputTouchEnd; /** Called when a finger is moved over this actor when touch over events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Touch Input") FActorBeginTouchOverSignature OnInputTouchEnter; /** Called when a finger is moved off this actor when touch over events are enabled in the player controller. */ UPROPERTY(BlueprintAssignable, Category="Input|Touch Input") FActorEndTouchOverSignature OnInputTouchLeave; /** * Called when this Actor hits (or is hit by) something solid. This could happen due to things like Character movement, using Set Location with 'sweep' enabled, or physics simulation. * For events when objects overlap (e.g. walking into a trigger) see the 'Overlap' event. * @note For collisions during physics simulation to generate hit events, 'Simulation Generates Hit Events' must be enabled. */ UPROPERTY(BlueprintAssignable, Category="Collision") FActorHitSignature OnActorHit; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API UActorComponent : public UObject, public IInterface_AssetUserData { /** Create component physics state global delegate.*/ static FActorComponentGlobalCreatePhysicsSignature GlobalCreatePhysicsDelegate; /** Destroy component physics state global delegate.*/ static FActorComponentGlobalDestroyPhysicsSignature GlobalDestroyPhysicsDelegate; /** Called when the component has been activated, with parameter indicating if it was from a reset */ UPROPERTY(BlueprintAssignable, Category = "Components|Activation") FActorComponentActivatedSignature OnComponentActivated; /** Called when the component has been deactivated */ UPROPERTY(BlueprintAssignable, Category = "Components|Activation") FActorComponentDeactivateSignature OnComponentDeactivated; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DECLARE_MULTICAST_DELEGATE_OneParam(FPawnChangedSignature, APawn* /*NewPawn*/); class ENGINE_API ULocalPlayer : public UPlayer { DECLARE_EVENT_TwoParams(ULocalPlayer, FOnControllerIdChanged, int32 /*NewId*/, int32 /*OldId*/); FOnControllerIdChanged& OnControllerIdChanged() const { return OnControllerIdChangedEvent; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API AController : public AActor, public INavAgentInterface { FInstigatedAnyDamageSignature OnInstigatedAnyDamage; FPawnChangedSignature& GetOnNewPawnNotifier() { return OnNewPawn; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API ACharacter : public APawn { /** Multicast delegate for MovementMode changing. */ UPROPERTY(BlueprintAssignable, Category=Character) FMovementModeChangedSignature MovementModeChangedDelegate; /** * Event triggered at the end of a CharacterMovementComponent movement update. * This is the preferred event to use rather than the Tick event when performing custom updates to CharacterMovement properties based on the current state. * This is mainly due to the nature of network updates, where client corrections in position from the server can cause multiple iterations of a movement update, * which allows this event to update as well, while a Tick event would not. * * @param DeltaSeconds Delta time in seconds for this update * @param InitialLocation Location at the start of the update. May be different than the current location if movement occurred. * @param InitialVelocity Velocity at the start of the update. May be different than the current velocity. */ UPROPERTY(BlueprintAssignable, Category=Character) FCharacterMovementUpdatedSignature OnCharacterMovementUpdated; /** Broadcast when Character's jump reaches its apex. Needs CharacterMovement->bNotifyApex = true */ UPROPERTY(BlueprintAssignable, Category=Character) FCharacterReachedApexSignature OnReachedJumpApex; /** * Called upon landing when falling, to perform actions based on the Hit result. * Note that movement mode is still "Falling" during this event. Current Velocity value is the velocity at the time of landing. * Consider OnMovementModeChanged() as well, as that can be used once the movement mode changes to the new mode (most likely Walking). * * @param Hit Result describing the landing that resulted in a valid landing spot. * @see OnMovementModeChanged() */ FLandedSignature LandedDelegate; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API AHUD : public AActor { // Callback allowing external systems to register to show debug info static FOnShowDebugInfo OnShowDebugInfo; // Called from ::PostRender. For less player/actor centered debugging static FOnHUDPostRender OnHUDPostRender; };
功能库
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// DECLARE_DELEGATE_ThreeParams(FLoadPackageAsyncDelegate, const FName& /*PackageName*/, UPackage* /*LoadedPackage*/, EAsyncLoadingResult::Type /*Result*/) /* Engine\Source\Runtime\CoreUObject\Public\UObject\UObjectGlobals.h **/ /** * Delegate called on completion of async package loading * @param PackageName Package name we were trying to load * @param LoadedPackage Loaded package if successful, nullptr otherwise * @param Result Result of async loading. */ DECLARE_DELEGATE_ThreeParams(FLoadPackageAsyncDelegate, const FName& /*PackageName*/, UPackage* /*LoadedPackage*/, EAsyncLoadingResult::Type /*Result*/) /** * Asynchronously load a package and all contained objects that match context flags. Non-blocking. * This version is useful when loading multiple copies of the same package. * * @param InName Name of package to load * @param InGuid GUID of the package to load, or nullptr for "don't care" * @param InPackageToLoadFrom If non-null, this is another package name. We load from this package name, into a (probably new) package named InName * @param InCompletionDelegate Delegate to be invoked when the packages has finished streaming * @param InPackageFlags Package flags used to construct loaded package in memory * @param InPIEInstanceID Play in Editor instance ID * @param InPackagePriority Loading priority * @return Unique ID associated with this load request (the same package can be associated with multiple IDs). */ COREUOBJECT_API int32 LoadPackageAsync(const FString& InName, const FGuid* InGuid = nullptr, const TCHAR* InPackageToLoadFrom = nullptr, FLoadPackageAsyncDelegate InCompletionDelegate = FLoadPackageAsyncDelegate(), EPackageFlags InPackageFlags = PKG_None, int32 InPIEInstanceID = INDEX_NONE, TAsyncLoadPriority InPackagePriority = 0); /** * Asynchronously load a package and all contained objects that match context flags. Non-blocking. * * @param InName Name of package to load * @param InCompletionDelegate Delegate to be invoked when the packages has finished streaming * @param InPackagePriority Loading priority * @param InPackageFlags Package flags used to construct loaded package in memory * @param InPIEInstanceID Play in Editor instance ID * @return Unique ID associated with this load request (the same package can be associated with multiple IDs). * * @see FStreamableManager for an engine-level wrapper */ COREUOBJECT_API int32 LoadPackageAsync(const FString& InName, FLoadPackageAsyncDelegate InCompletionDelegate, TAsyncLoadPriority InPackagePriority = 0, EPackageFlags InPackageFlags = PKG_None, int32 InPIEInstanceID = INDEX_NONE); /** * Cancels all async package loading requests. */ COREUOBJECT_API void CancelAsyncLoading(); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class UObjectLibrary : public UObject { DECLARE_EVENT_OneParam(UObjectLibrary, FObjectLibraryOnObjectAdded, UObject* /*NewObject*/); FObjectLibraryOnObjectAdded& OnObjectAdded() { return OnObjectAddedEvent; } DECLARE_EVENT_OneParam(UObjectLibrary, FObjectLibraryOnObjectRemoved, UObject* /*ObjectToRemove*/); FObjectLibraryOnObjectRemoved& OnObjectRemoved() { return OnObjectRemovedEvent; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class UMG_API UWidgetBlueprintLibrary : public UBlueprintFunctionLibrary { DECLARE_DYNAMIC_DELEGATE(FOnGameWindowCloseButtonClickedDelegate); UFUNCTION(BlueprintCallable, Category = "Widget|Window Title Bar") static void SetWindowTitleBarOnCloseClickedDelegate(FOnGameWindowCloseButtonClickedDelegate Delegate); }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class ENGINE_API UKismetSystemLibrary : public UBlueprintFunctionLibrary { DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAssetLoaded, class UObject*, Loaded); UFUNCTION(BlueprintCallable, meta = (Latent, LatentInfo = "LatentInfo", WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Utilities") static void LoadAsset(UObject* WorldContextObject, TSoftObjectPtr<UObject> Asset, FOnAssetLoaded OnLoaded, FLatentActionInfo LatentInfo); DECLARE_DYNAMIC_DELEGATE_OneParam(FOnAssetClassLoaded, TSubclassOf<UObject>, Loaded); UFUNCTION(BlueprintCallable, meta = (Latent, LatentInfo = "LatentInfo", WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Utilities") static void LoadAssetClass(UObject* WorldContextObject, TSoftClassPtr<UObject> AssetClass, FOnAssetClassLoaded OnLoaded, FLatentActionInfo LatentInfo); }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** Delegate called when a notify was replaced */ DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnNotifyReplaced, UAnimNotify*, OldNotify, UAnimNotify*, NewNotify); /** Delegate called when a notify state was replaced */ DECLARE_DYNAMIC_DELEGATE_TwoParams(FOnNotifyStateReplaced, UAnimNotifyState*, OldNotifyState, UAnimNotifyState*, NewNotifyState); /** Blueprint library for altering and analyzing animation / skeletal data */ class ANIMATIONMODIFIERS_API UAnimationBlueprintLibrary : public UBlueprintFunctionLibrary { /** Replaces animation notifies in the specified Animation Sequence */ UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents") static void ReplaceAnimNotifyStates(UAnimSequenceBase* AnimationSequence, TSubclassOf<UAnimNotifyState> OldNotifyClass, TSubclassOf<UAnimNotifyState> NewNotifyClass, FOnNotifyStateReplaced OnNotifyStateReplaced); /** Replaces animation notifies in the specified Animation Sequence */ UFUNCTION(BlueprintCallable, Category = "AnimationBlueprintLibrary|NotifyEvents") static void ReplaceAnimNotifies(UAnimSequenceBase* AnimationSequence, TSubclassOf<UAnimNotify> OldNotifyClass, TSubclassOf<UAnimNotify> NewNotifyClass, FOnNotifyReplaced OnNotifyReplaced); };