Files
UnrealEngineUWP/Engine/Source/Runtime/MessagingCommon/Public/MessageEndpoint.h
robert manuszewski d1443992e1 Deprecating ANY_PACKAGE.
This change consists of multiple changes:

Core:
- Deprecation of ANY_PACKAGE macro. Added ANY_PACKAGE_DEPRECATED macro which can still be used for backwards compatibility purposes (only used in CoreUObject)
- Deprecation of StaticFindObjectFast* functions that take bAnyPackage parameter
- Added UStruct::GetStructPathName function that returns FTopLevelAssetPath representing the path name (package + object FName, super quick compared to UObject::GetPathName) + wrapper UClass::GetClassPathName to make it look better when used with UClasses
- Added (Static)FindFirstObject* functions that find a first object given its Name (no Outer). These functions are used in places I consider valid to do global UObject (UClass) lookups like parsing command line parameters / checking for unique object names
- Added static UClass::TryFindType function which serves a similar purpose as FindFirstObject however it's going to throw a warning (with a callstack / maybe ensure in the future?) if short class name is provided. This function is used  in places that used to use short class names but now should have been converted to use path names to catch any potential regressions and or edge cases I missed.
- Added static UClass::TryConvertShortNameToPathName utility function
- Added static UClass::TryFixShortClassNameExportPath utility function
- Object text export paths will now also include class path (Texture2D'/Game/Textures/Grass.Grass' -> /Script/Engine.Texture2D'/Game/Textures/Grass.Grass')
- All places that manually generated object export paths for objects will now use FObjectPropertyBase::GetExportPath
- Added a new startup test that checks for short type names in UClass/FProperty MetaData values

AssetRegistry:
- Deprecated any member variables (FAssetData / FARFilter) or functions that use FNames to represent class names and replaced them with FTopLevelAssetPath
- Added new member variables and new function overloads that use FTopLevelAssetPath to represent class names
- This also applies to a few other modules' APIs to match AssetRegistry changes

Everything else:
- Updated code that used ANY_PACKAGE (depending on the use case) to use FindObject(nullptr, PathToObject), UClass::TryFindType (used when path name is expected, warns if it's a short name) or FindFirstObject (usually for finding types based on user input but there's been a few legitimate use cases not related to user input)
- Updated code that used AssetRegistry API to use FTopLevelAssetPaths and USomeClass::StaticClass()->GetClassPathName() instead of GetFName()
- Updated meta data and hardcoded FindObject(ANY_PACKAGE, "EEnumNameOrClassName") calls to use path names

#jira UE-99463
#rb many.people
[FYI] Marcus.Wassmer
#preflight 629248ec2256738f75de9b32

#codereviewnumbers 20320742, 20320791, 20320799, 20320756, 20320809, 20320830, 20320840, 20320846, 20320851, 20320863, 20320780, 20320765, 20320876, 20320786

#ROBOMERGE-OWNER: robert.manuszewski
#ROBOMERGE-AUTHOR: robert.manuszewski
#ROBOMERGE-SOURCE: CL 20430220 via CL 20433854 via CL 20435474 via CL 20435484
#ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v949-20362246)

[CL 20448496 by robert manuszewski in ue5-main branch]
2022-06-01 03:46:59 -04:00

1066 lines
36 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreTypes.h"
#include "Async/TaskGraphInterfaces.h"
#include "Containers/Array.h"
#include "Containers/ArrayBuilder.h"
#include "Containers/Queue.h"
#include "IMessageAttachment.h"
#include "IMessageBus.h"
#include "IMessageContext.h"
#include "IMessageHandler.h"
#include "IMessageReceiver.h"
#include "IMessageSender.h"
#include "IMessageBusListener.h"
#include "Misc/Guid.h"
#include "Templates/SharedPointer.h"
#include "UObject/NameTypes.h"
#include "Misc/ScopeLock.h"
/**
* DEPRECATED: Delegate type for error notifications.
*
* The first parameter is the context of the sent message (only valid for the duration of the callback).
* The second parameter is the error string.
*/
DECLARE_DELEGATE_TwoParams(FOnMessageEndpointError, const IMessageContext&, const FString&);
/**
* Struct to propagate message bus notifications
*/
struct FMessageBusNotification
{
/** Notification type. */
EMessageBusNotification NotificationType;
/** Address of the un/registered. */
FMessageAddress RegistrationAddress;
};
/** Delegate type for MessageBus notifications. */
DECLARE_DELEGATE_OneParam(FOnBusNotification, const FMessageBusNotification&);
/**
* Implements a message endpoint for sending and receiving messages on a message bus.
*
* This class provides a convenient implementation of the IMessageReceiver and IMessageSender interfaces,
* which allow consumers to send and receive messages on a message bus. The endpoint allows for receiving
* messages asynchronously as they arrive, as well as synchronously through an inbox that can be polled.
*
* By default, messages are received synchronously on the thread that the endpoint was created on.
* If the message consumer is thread-safe, a more efficient message dispatch can be enabled by calling
* the SetRecipientThread() method with ENamedThreads::AnyThread.
*
* Endpoints that are destroyed or receive messages on non-Game threads should use the static function
* FMessageEndpoint::SafeRelease() to dispose of the endpoint. This will ensure that there are no race
* conditions between endpoint destruction and the receiving of messages.
*
* The underlying message bus will take ownership of all sent and published message objects. The memory
* held by the messages must therefore NOT be freed by the caller.
*/
class FMessageEndpoint
: public TSharedFromThis<FMessageEndpoint, ESPMode::ThreadSafe>
, public IMessageReceiver
, public IMessageSender
, public IBusListener
{
public:
/**
* Type definition for the endpoint builder.
*
* When building message endpoints that receive messages on AnyThread, use the SafeRelease
* helper function to avoid race conditions when destroying the objects that own the endpoints.
*
* @see SafeRelease
*/
typedef struct FMessageEndpointBuilder Builder;
/**
* Creates and initializes a new instance.
*
* @param InName The endpoint's name (for debugging purposes).
* @param InBus The message bus to attach this endpoint to.
* @param InHandlers The collection of message handlers to register.
*/
FMessageEndpoint(const FName& InName, const TSharedRef<IMessageBus, ESPMode::ThreadSafe>& InBus, const TArray<TSharedPtr<IMessageHandler, ESPMode::ThreadSafe>>& InHandlers, const FOnBusNotification InNotificationDelegate)
: Address(FMessageAddress::NewAddress())
, BusPtr(InBus)
, Enabled(true)
, Handlers(InHandlers)
, NotificationDelegate(InNotificationDelegate)
, Id(FGuid::NewGuid())
, InboxEnabled(false)
, Name(InName)
{
SetRecipientThread(FTaskGraphInterface::Get().GetCurrentThreadIfKnown());
}
/** Destructor. */
~FMessageEndpoint()
{
auto Bus = BusPtr.Pin();
if (Bus.IsValid())
{
Bus->Unregister(Address);
}
}
public:
/**
* Disables this endpoint.
*
* A disabled endpoint will not receive any subscribed messages until it is enabled again.
* Endpoints should be created in an enabled state by default.
*
* @see Enable, IsEnabled
*/
void Disable()
{
Enabled = false;
}
/**
* Enables this endpoint.
*
* An activated endpoint will receive subscribed messages.
* Endpoints should be created in an enabled state by default.
*
* @see Disable, IsEnabled
*/
void Enable()
{
Enabled = true;
}
/**
* Gets the endpoint's message address.
*
* @return Message address.
*/
const FMessageAddress& GetAddress() const
{
return Address;
}
/**
* Checks whether this endpoint is connected to the bus.
*
* @return true if connected, false otherwise.
* @see IsEnabled
*/
bool IsConnected() const
{
return BusPtr.IsValid();
}
/**
* Checks whether this endpoint is enabled.
*
* @return true if the endpoint is enabled, false otherwise.
* @see Disable, Enable, IsConnected
*/
bool IsEnabled() const
{
return Enabled;
}
/**
* Sets the name of the thread to receive messages on.
*
* Use this method to receive messages on a particular thread, for example, if the
* consumer owning this endpoint is not thread-safe. The default value is ThreadAny.
*
* ThreadAny is the fastest way to receive messages. It should be used if the receiving
* code is completely thread-safe and if it is sufficiently fast. ThreadAny MUST NOT
* be used if the receiving code is not thread-safe. It also SHOULD NOT be used if the
* code includes time consuming operations, because it will block the message router,
* causing no other messages to be delivered in the meantime.
*
* @param NamedThread The name of the thread to receive messages on.
*/
void SetRecipientThread(const ENamedThreads::Type& NamedThread)
{
RecipientThread = ENamedThreads::GetThreadIndex(NamedThread);
}
public:
/**
* Defers processing of the given message by the specified time delay.
*
* The message is effectively delivered again to this endpoint after the
* original sent time plus the time delay have elapsed.
*
* @param Context The context of the message to defer.
* @param Delay The time delay.
*/
void Defer(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FTimespan& Delay)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Forward(Context, TArrayBuilder<FMessageAddress>().Add(Address), Delay, AsShared());
}
}
/**
* Forwards a previously received message.
*
* Messages can only be forwarded to endpoints within the same process.
*
* @param Context The context of the message to forward.
* @param Recipients The list of message recipients to forward the message to.
* @param Delay The time delay.
*/
void Forward(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Forward(Context, Recipients, Delay, AsShared());
}
}
/**
* Publishes a message to all subscribed recipients within the specified scope.
*
* @param Message The message to publish.
* @param TypeInfo The message's type information.
* @param Scope The message scope.
* @param Fields The message content.
* @param Delay The delay after which to publish the message.
* @param Expiration The time at which the message expires.
*/
void Publish(void* Message, UScriptStruct* TypeInfo, EMessageScope Scope, const FTimespan& Delay, const FDateTime& Expiration)
{
Publish(Message, TypeInfo, Scope, TMap<FName, FString>(), Delay, Expiration);
}
/**
* Publishes a message to all subscribed recipients within the specified scope.
*
* @param Message The message to publish.
* @param TypeInfo The message's type information.
* @param Scope The message scope.
* @param Annotations An optional message annotations header.
* @param Fields The message content.
* @param Delay The delay after which to publish the message.
* @param Expiration The time at which the message expires.
*/
void Publish(void* Message, UScriptStruct* TypeInfo, EMessageScope Scope, const TMap<FName, FString> Annotations, const FTimespan& Delay, const FDateTime& Expiration)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Publish(Message, TypeInfo, Scope, Annotations, Delay, Expiration, AsShared());
}
}
/**
* Sends a message to the specified list of recipients.
*
* @param Message The message to send.
* @param TypeInfo The message's type information.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
*/
UE_DEPRECATED(4.21, "FMessageEndpoint::Send with 6 params is deprecated. Please use FMessageEndpoint::Send that takes additionnal EMessageFlags instead!")
void Send(void* Message, UScriptStruct* TypeInfo, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration)
{
Send(Message, TypeInfo, EMessageFlags::None, Attachment, Recipients, Delay, Expiration);
}
/**
* Sends a message to the specified list of recipients.
* Allows to specify message flags
*
* @param Message The message to send.
* @param TypeInfo The message's type information.
* @param Flags The message's type information.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
*/
void Send(void* Message, UScriptStruct* TypeInfo, EMessageFlags Flags, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Send(Message, TypeInfo, Flags, TMap<FName, FString>(), Attachment, Recipients, Delay, Expiration, AsShared());
}
}
/**
* Sends a message to the specified list of recipients.
*
* @param Message The message to send.
* @param TypeInfo The message's type information.
* @param Flags The message's type information.
* @param Annotations An optional message annotations header.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
*/
void Send(void* Message, UScriptStruct* TypeInfo, EMessageFlags Flags, const TMap<FName, FString> Annotations, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Send(Message, TypeInfo, Flags, Annotations, Attachment, Recipients, Delay, Expiration, AsShared());
}
}
/**
* Subscribes a message handler.
*
* @param MessageType The type name of the messages to subscribe to.
* @param ScopeRange The range of message scopes to include in the subscription.
*/
UE_DEPRECATED(5.1, "Types names are now represented by path names. Please use a version of this function that takes an FTopLevelAssetPath as MessageType.")
void Subscribe(const FName& MessageType, const FMessageScopeRange& ScopeRange)
{
Subscribe(UClass::TryConvertShortTypeNameToPathName<UStruct>(MessageType.ToString()), ScopeRange);
}
/**
* Subscribes a message handler.
*
* @param MessageType The type name of the messages to subscribe to.
* @param ScopeRange The range of message scopes to include in the subscription.
*/
void Subscribe(const FTopLevelAssetPath& MessageType, const FMessageScopeRange& ScopeRange)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Subscribe(AsShared(), MessageType, ScopeRange);
}
}
/**
* Unsubscribes this endpoint from the specified message type.
*
* @param MessageType The type of message to unsubscribe (IMessageBus::PATHNAME_All = all types).
* @see Subscribe
*/
UE_DEPRECATED(5.1, "Types names are now represented by path names. Please use a version of this function that takes an FTopLevelAssetPath as MessageType.")
void Unsubscribe(const FName& MessageType)
{
Unsubscribe(UClass::TryConvertShortTypeNameToPathName<UStruct>(MessageType.ToString()));
}
/**
* Unsubscribes this endpoint from the specified message type.
*
* @param MessageType The type of message to unsubscribe (IMessageBus::PATHNAME_All = all types).
* @see Subscribe
*/
void Unsubscribe(const FTopLevelAssetPath& MessageType)
{
TSharedPtr<IMessageBus, ESPMode::ThreadSafe> Bus = GetBusIfEnabled();
if (Bus.IsValid())
{
Bus->Unsubscribe(AsShared(), MessageType);
}
}
public:
/**
* Disables the inbox for unhandled messages.
*
* The inbox is disabled by default.
*
* @see EnableInbox, IsInboxEmpty, IsInboxEnabled, ProcessInbox, ReceiveFromInbox
*/
void DisableInbox()
{
InboxEnabled = false;
}
/**
* Enables the inbox for unhandled messages.
*
* If enabled, the inbox will queue up all received messages. Use ProcessInbox() to synchronously
* invoke the registered message handlers for all queued up messages, or ReceiveFromInbox() to
* manually receive one message from the inbox at a time. The inbox is disabled by default.
*
* @see DisableInbox, IsInboxEmpty, IsInboxEnabled, ProcessInbox, ReceiveFromInbox
*/
void EnableInbox()
{
InboxEnabled = true;
}
/**
* Checks whether the inbox is empty.
*
* @return true if the inbox is empty, false otherwise.
* @see DisableInbox, EnableInbox, IsInboxEnabled, ProcessInbox, ReceiveFromInbox
*/
bool IsInboxEmpty() const
{
return Inbox.IsEmpty();
}
/**
* Checks whether the inbox is enabled.
*
* @see DisableInbox, EnableInbox, IsInboxEmpty, ProcessInbox, ReceiveFromInbox
*/
bool IsInboxEnabled() const
{
return InboxEnabled;
}
/**
* Calls the matching message handlers for all messages queued up in the inbox.
*
* Note that an incoming message will only be queued up in the endpoint's inbox if the inbox has
* been enabled and no matching message handler handled it. The inbox is disabled by default and
* must be enabled using the EnableInbox() method.
*
* @see IsInboxEmpty, ReceiveFromInbox
*/
void ProcessInbox()
{
TSharedPtr<IMessageContext, ESPMode::ThreadSafe> Context;
while (Inbox.Dequeue(Context))
{
ProcessMessage(Context.ToSharedRef());
}
}
/**
* Receives a single message from the endpoint's inbox.
*
* Note that an incoming message will only be queued up in the endpoint's inbox if the inbox has
* been enabled and no matching message handler handled it. The inbox is disabled by default and
* must be enabled using the EnableInbox() method.
*
* @param OutContext Will hold the context of the received message.
* @return true if a message was received, false if the inbox was empty.
* @see DisableInbox, EnableInbox, IsInboxEnabled, ProcessInbox
*/
bool ReceiveFromInbox(TSharedPtr<IMessageContext, ESPMode::ThreadSafe>& OutContext)
{
return Inbox.Dequeue(OutContext);
}
public:
//~ IMessageReceiver interface
virtual FName GetDebugName() const override
{
return Name;
}
virtual const FGuid& GetRecipientId() const override
{
return Id;
}
virtual ENamedThreads::Type GetRecipientThread() const override
{
return RecipientThread;
}
virtual bool IsLocal() const override
{
return true;
}
virtual void ReceiveMessage(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context) override
{
if (!Enabled)
{
return;
}
if (InboxEnabled)
{
Inbox.Enqueue(Context);
}
else
{
ProcessMessage(Context);
}
}
//~ IBusListener interface
virtual ENamedThreads::Type GetListenerThread() const override
{
return RecipientThread;
}
virtual void NotifyRegistration(const FMessageAddress& InAddress, EMessageBusNotification InNotification)
{
if (!Enabled)
{
return;
}
NotificationDelegate.ExecuteIfBound(FMessageBusNotification{ InNotification, InAddress });
}
public:
//~ IMessageSender interface
virtual FMessageAddress GetSenderAddress() override
{
return Address;
}
virtual void NotifyMessageError(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FString& Error) override
{
ErrorDelegate.ExecuteIfBound(Context.Get(), Error);
}
public:
/**
* Creates a message of the specified template type.
*
* Prefer using this helper rather than explicit new. See FEngineServicePong.
*
* @param Args The constructor arguments to the template type
*/
template<typename T, typename... InArgTypes>
static T* MakeMessage(InArgTypes&&... Args)
{
void* Buffer = FMemory::Malloc(sizeof(T));
T* Message = new (Buffer) T(::Forward<InArgTypes>(Args)...);
return Message;
}
/**
* Immediately forwards a previously received message to the specified recipient.
*
* Messages can only be forwarded to endpoints within the same process.
*
* @param Context The context of the message to forward.
* @param Recipient The address of the recipient to forward the message to.
*/
void Forward(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FMessageAddress& Recipient)
{
Forward(Context, TArrayBuilder<FMessageAddress>().Add(Recipient), FTimespan::Zero());
}
/**
* Forwards a previously received message to the specified recipient after a given delay.
*
* Messages can only be forwarded to endpoints within the same process.
*
* @param Context The context of the message to forward.
* @param Recipient The address of the recipient to forward the message to.
* @param ForwardingScope The scope of the forwarded message.
* @param Delay The delay after which to publish the message.
*/
void Forward(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FMessageAddress& Recipient, const FTimespan& Delay)
{
Forward(Context, TArrayBuilder<FMessageAddress>().Add(Recipient), Delay);
}
/**
* Immediately forwards a previously received message to the specified list of recipients.
*
* Messages can only be forwarded to endpoints within the same process.
*
* @param Context The context of the message to forward.
* @param Recipients The list of message recipients to forward the message to.
* @param ForwardingScope The scope of the forwarded message.
*/
void Forward(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const TArray<FMessageAddress>& Recipients)
{
Forward(Context, Recipients, FTimespan::Zero());
}
/**
* Immediately publishes a message to all subscribed recipients.
*
* @param Message The message to publish.
*/
template<typename MessageType>
void Publish(MessageType* Message)
{
Publish(Message, MessageType::StaticStruct(), EMessageScope::Network, FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Immediately pa message to all subscribed recipients within the specified scope.
*
* @param Message The message to publish.
* @param Scope The message scope.
*/
template<typename MessageType>
void Publish(MessageType* Message, EMessageScope Scope)
{
Publish(Message, MessageType::StaticStruct(), Scope, FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Immediately publishes a message to all subscribed recipients.
*
* @param Message The message to publish.
* @param Annotations An optional message annotations header.
*/
template<typename MessageType>
void Publish(MessageType* Message, const TMap<FName, FString> Annotations)
{
Publish(Message, MessageType::StaticStruct(), Annotations, EMessageScope::Network, FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Immediately pa message to all subscribed recipients within the specified scope.
*
* @param Message The message to publish.
* @param Annotations An optional message annotations header.
* @param Scope The message scope.
*/
template<typename MessageType>
void Publish(MessageType* Message, const TMap<FName, FString> Annotations, EMessageScope Scope)
{
Publish(Message, MessageType::StaticStruct(), Annotations, Scope, FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Publishes a message to all subscribed recipients after a given delay.
*
* @param Message The message to publish.
* @param Delay The delay after which to publish the message.
*/
template<typename MessageType>
void Publish(MessageType* Message, const FTimespan& Delay)
{
Publish(Message, MessageType::StaticStruct(), EMessageScope::Network, Delay, FDateTime::MaxValue());
}
/**
* Publishes a message to all subscribed recipients within the specified scope after a given delay.
*
* @param Message The message to publish.
* @param Scope The message scope.
* @param Delay The delay after which to publish the message.
*/
template<typename MessageType>
void Publish(MessageType* Message, EMessageScope Scope, const FTimespan& Delay)
{
Publish(Message, MessageType::StaticStruct(), Scope, Delay, FDateTime::MaxValue());
}
/**
* Publishes a message to all subscribed recipients within the specified scope.
*
* @param Message The message to publish.
* @param Scope The message scope.
* @param Fields The message content.
* @param Delay The delay after which to publish the message.
* @param Expiration The time at which the message expires.
*/
template<typename MessageType>
void Publish(MessageType* Message, EMessageScope Scope, const FTimespan& Delay, const FDateTime& Expiration)
{
Publish(Message, MessageType::StaticStruct(), Scope, Delay, Expiration);
}
/**
* Publishes a message to all subscribed recipients within the specified scope.
*
* @param Message The message to publish.
* @param Annotations An optional message annotations header.
* @param Scope The message scope.
* @param Fields The message content.
* @param Delay The delay after which to publish the message.
* @param Expiration The time at which the message expires.
*/
template<typename MessageType>
void Publish(MessageType* Message, const TMap<FName, FString> Annotations, EMessageScope Scope, const FTimespan& Delay, const FDateTime& Expiration)
{
Publish(Message, MessageType::StaticStruct(), Annotations, Scope, Delay, Expiration);
}
/**
* Immediately sends a message to the specified recipient.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Recipient The message recipient.
*/
template<typename MessageType>
void Send(MessageType* Message, const FMessageAddress& Recipient)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, nullptr, TArrayBuilder<FMessageAddress>().Add(Recipient), FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Immediately sends a message to the specified recipient.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Annotations An optional message annotations header.
* @param Recipient The message recipient.
*/
template<typename MessageType>
void Send(MessageType* Message, const TMap<FName, FString> Annotations, const FMessageAddress& Recipient)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, Annotations, nullptr, TArrayBuilder<FMessageAddress>().Add(Recipient), FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Sends a message to the specified recipient after a given delay.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Recipient The message recipient.
* @param Delay The delay after which to send the message.
*/
template<typename MessageType>
void Send(MessageType* Message, const FMessageAddress& Recipient, const FTimespan& Delay)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, nullptr, TArrayBuilder<FMessageAddress>().Add(Recipient), Delay, FDateTime::MaxValue());
}
/**
* Sends a message with fields and expiration to the specified recipient after a given delay.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Recipient The message recipient.
* @param Expiration The time at which the message expires.
* @param Delay The delay after which to send the message.
*/
template<typename MessageType>
void Send(MessageType* Message, const FMessageAddress& Recipient, const FTimespan& Delay, const FDateTime& Expiration)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, nullptr, TArrayBuilder<FMessageAddress>().Add(Recipient), Delay, Expiration);
}
/**
* Sends a message with fields and attachment to the specified recipient.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Attachment An optional binary data attachment.
* @param Recipient The message recipient.
*/
template<typename MessageType>
void Send(MessageType* Message, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const FMessageAddress& Recipient)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, Attachment, TArrayBuilder<FMessageAddress>().Add(Recipient), FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Sends a message with fields, attachment and expiration to the specified recipient after a given delay.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Attachment An optional binary data attachment.
* @param Recipient The message recipient.
* @param Expiration The time at which the message expires.
* @param Delay The delay after which to send the message.
*/
template<typename MessageType>
void Send(MessageType* Message, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const FMessageAddress& Recipient, const FDateTime& Expiration, const FTimespan& Delay)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, Attachment, TArrayBuilder<FMessageAddress>().Add(Recipient), Delay, Expiration);
}
/**
* Sends a message with fields, attachment and expiration to the specified recipient after a given delay.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Annotations An optional message annotations header.
* @param Attachment An optional binary data attachment.
* @param Recipient The message recipient.
* @param Expiration The time at which the message expires.
* @param Delay The delay after which to send the message.
*/
template<typename MessageType>
void Send(MessageType* Message, const TMap<FName, FString> Annotations, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const FMessageAddress& Recipient, const FDateTime& Expiration, const FTimespan& Delay)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, Annotations, Attachment, TArrayBuilder<FMessageAddress>().Add(Recipient), Delay, Expiration);
}
/**
* Immediately sends a message to the specified list of recipients.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Recipients The message recipients.
*/
template<typename MessageType>
void Send(MessageType* Message, const TArray<FMessageAddress>& Recipients)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, nullptr, Recipients, FTimespan::Zero(), FDateTime::MaxValue());
}
/**
* Sends a message to the specified list of recipients after a given delay after a given delay.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
*/
template<typename MessageType>
void Send(MessageType* Message, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, nullptr, Recipients, Delay, FDateTime::MaxValue());
}
/**
* Sends a message with fields and attachment to the specified list of recipients after a given delay.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
*/
template<typename MessageType>
void Send(MessageType* Message, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, Attachment, Recipients, Delay, FDateTime::MaxValue());
}
/**
* Sends a message to the specified list of recipients.
*
* @param MessageType The type of message to send.
* @param Message The message to send.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
*/
template<typename MessageType>
void Send(MessageType* Message, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration)
{
Send(Message, MessageType::StaticStruct(), EMessageFlags::None, Attachment, Recipients, Delay, Expiration);
}
/**
* Sends a message to the specified list of recipients.
* Allows to specify message flags
*
* @param Message The message to send.
* @param TypeInfo The message's type information.
* @param Flags The message's type information.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
*/
template<typename MessageType>
void Send(MessageType* Message, EMessageFlags Flags, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration)
{
Send(Message, MessageType::StaticStruct(), Flags, Attachment, Recipients, Delay, Expiration);
}
/**
* Sends a message to the specified list of recipients.
* Allows to specify message flags
*
* @param Message The message to send.
* @param TypeInfo The message's type information.
* @param Flags The message's type information.
* @param Annotations An optional message annotations header.
* @param Attachment An optional binary data attachment.
* @param Recipients The message recipients.
* @param Delay The delay after which to send the message.
* @param Expiration The time at which the message expires.
*/
template<typename MessageType>
void Send(MessageType* Message, EMessageFlags Flags, const TMap<FName, FString> Annotations, const TSharedPtr<IMessageAttachment, ESPMode::ThreadSafe>& Attachment, const TArray<FMessageAddress>& Recipients, const FTimespan& Delay, const FDateTime& Expiration)
{
Send(Message, MessageType::StaticStruct(), Flags, Annotations, Attachment, Recipients, Delay, Expiration);
}
/**
* Template method to subscribe the message endpoint to the specified type of messages with the default message scope.
*
* The default message scope is all messages excluding loopback messages.
*
* @param HandlerType The type of the class handling the message.
* @param MessageType The type of messages to subscribe to.
* @param Handler The class handling the messages.
* @param HandlerFunc The class function handling the messages.
*/
template<class MessageType>
void Subscribe()
{
Subscribe(MessageType::StaticStruct()->GetStructPathName(), FMessageScopeRange::AtLeast(EMessageScope::Thread));
}
/**
* Template method to subscribe the message endpoint to the specified type and scope of messages.
*
* @param HandlerType The type of the class handling the message.
* @param MessageType The type of messages to subscribe to.
* @param Handler The class handling the messages.
* @param HandlerFunc The class function handling the messages.
* @param ScopeRange The range of message scopes to include in the subscription.
*/
template<class MessageType>
void Subscribe(const FMessageScopeRange& ScopeRange)
{
Subscribe(MessageType::StaticStruct()->GetStructPathName(), ScopeRange);
}
/**
* Unsubscribes this endpoint from all message types.
*
* @see Subscribe
*/
void Unsubscribe()
{
Unsubscribe(IMessageBus::PATHNAME_All);
}
/**
* Template method to unsubscribe the endpoint from the specified message type.
*
* @param MessageType The type of message to unsubscribe (IMessageBus::PATHNAME_All = all types).
* @see Subscribe
*/
template<class MessageType>
void Unsubscribe()
{
Unsubscribe(MessageType::StaticStruct()->GetStructPathName());
}
public:
/**
* Safely releases a message endpoint that is receiving messages on AnyThread.
*
* When an object that owns a message endpoint receiving on AnyThread is being destroyed,
* it is possible that the endpoint can outlive the object for a brief period of time if
* the Messaging system is dispatching messages to it. This helper function
* is to block the calling thread while any messages are being dispatched, so that the
* endpoint does not invoke any message handlers after the object has been destroyed.
*
* @param Endpoint The message endpoint to release.
*/
static void SafeRelease(TSharedPtr<FMessageEndpoint, ESPMode::ThreadSafe>& Endpoint)
{
if (Endpoint.IsValid())
{
Endpoint->ClearHandlers();
Endpoint.Reset();
}
}
protected:
/**
* Clears all handlers in a way that guarantees it won't overlap with message processing. This preserves internal integrity
* of the array and cases where our owner may be shutting down while receiving messages.
*/
void ClearHandlers()
{
FScopeLock Lock(&HandlersCS);
Handlers.Empty();
}
/**
* Gets a shared pointer to the message bus if this endpoint is enabled.
*
* @return The message bus.
*/
FORCEINLINE TSharedPtr<IMessageBus, ESPMode::ThreadSafe> GetBusIfEnabled() const
{
if (Enabled)
{
return BusPtr.Pin();
}
return nullptr;
}
/**
* Forwards the given message context to matching message handlers.
*
* @param Context The context of the message to handle.
*/
void ProcessMessage(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context)
{
if (!Context->IsValid())
{
return;
}
FScopeLock Lock(&HandlersCS);
for (int32 HandlerIndex = 0; HandlerIndex < Handlers.Num(); ++HandlerIndex)
{
Handlers[HandlerIndex]->HandleMessage(Context);
}
}
private:
/** Holds the endpoint's identifier. */
const FMessageAddress Address;
/** Holds a weak pointer to the message bus. */
TWeakPtr<IMessageBus, ESPMode::ThreadSafe> BusPtr;
/** Hold a flag indicating whether this endpoint is active. */
bool Enabled;
/** Holds the registered message handlers. */
TArray<TSharedPtr<IMessageHandler, ESPMode::ThreadSafe>> Handlers;
/** Holds a delegate that is invoked on disconnection events. */
FOnBusNotification NotificationDelegate;
/** Holds the endpoint's unique identifier (for debugging purposes). */
const FGuid Id;
/** Holds the endpoint's message inbox. */
TQueue<TSharedPtr<IMessageContext, ESPMode::ThreadSafe>, EQueueMode::Mpsc> Inbox;
/** Holds a flag indicating whether the inbox is enabled. */
bool InboxEnabled;
/** Holds the endpoint's name (for debugging purposes). */
const FName Name;
/** Holds the name of the thread on which to receive messages. */
ENamedThreads::Type RecipientThread;
private:
/** Holds a delegate that is invoked in case of messaging errors. */
FOnMessageEndpointError ErrorDelegate;
/** Sigfnifies that the handler array is being accessed and other threads should wait or skip */
FCriticalSection HandlersCS;
};