Files
UnrealEngine/Engine/Source/Runtime/Messaging/Private/Bus/MessageBus.cpp
2025-05-18 13:04:45 +08:00

264 lines
7.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Bus/MessageBus.h"
#include "IMessagingModule.h"
#include "HAL/RunnableThread.h"
#include "Bus/MessageRouter.h"
#include "Bus/MessageContext.h"
#include "Bus/MessageSubscription.h"
#include "IMessageSender.h"
#include "IMessageReceiver.h"
#include "HAL/ThreadSingleton.h"
const FTopLevelAssetPath IMessageBus::PATHNAME_All(TEXT("/Unknown"), NAME_All);
/* FMessageBus structors
*****************************************************************************/
FMessageBus::FMessageBus(FString InName, const TSharedPtr<IAuthorizeMessageRecipients>& InRecipientAuthorizer)
: Name(MoveTemp(InName))
, RecipientAuthorizer(InRecipientAuthorizer)
{
Router = new FMessageRouter();
RouterThread = FRunnableThread::Create(Router, *FString::Printf(TEXT("FMessageBus.%s.Router"), *Name), 128 * 1024, TPri_Normal, FPlatformAffinity::GetPoolThreadMask());
check(Router != nullptr);
}
FMessageBus::~FMessageBus()
{
Shutdown();
delete Router;
}
/* IMessageBus interface
*****************************************************************************/
void FMessageBus::Forward(
const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context,
const TArray<FMessageAddress>& Recipients,
const FTimespan& Delay,
const TSharedRef<IMessageSender, ESPMode::ThreadSafe>& Forwarder
)
{
if (UE_GET_LOG_VERBOSITY(LogMessaging) >= ELogVerbosity::Verbose)
{
FString RecipientStr = FString::JoinBy(Context->GetRecipients(), TEXT("+"), &FMessageAddress::ToString);
UE_LOG(LogMessaging, Verbose, TEXT("Forwarding %s from %s to %s"),
*Context->GetMessageTypePathName().ToString(),
*Context->GetSender().ToString(), *RecipientStr);
}
Router->RouteMessage(MakeShareable(new FMessageContext(
Context,
Forwarder->GetSenderAddress(),
Recipients,
EMessageScope::Process,
FDateTime::UtcNow() + Delay,
FTaskGraphInterface::Get().GetCurrentThreadIfKnown()
)));
}
TSharedRef<IMessageTracer, ESPMode::ThreadSafe> FMessageBus::GetTracer()
{
return Router->GetTracer();
}
void FMessageBus::Intercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FTopLevelAssetPath& MessageType)
{
if (MessageType.IsNull())
{
return;
}
if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeInterceptor(Interceptor, MessageType))
{
UE_LOG(LogMessaging, Verbose, TEXT("Adding invterceptor %s"), *Interceptor->GetDebugName().ToString());
Router->AddInterceptor(Interceptor, MessageType);
}
}
FOnMessageBusShutdown& FMessageBus::OnShutdown()
{
return ShutdownDelegate;
}
void FMessageBus::Publish(
void* Message,
UScriptStruct* TypeInfo,
EMessageScope Scope,
const TMap<FName, FString>& Annotations,
const FTimespan& Delay,
const FDateTime& Expiration,
const TSharedRef<IMessageSender, ESPMode::ThreadSafe>& Publisher
)
{
UE_LOG(LogMessaging, Verbose, TEXT("Publishing %s from sender %s"), *TypeInfo->GetName(), *Publisher->GetSenderAddress().ToString());
Router->RouteMessage(MakeShared<FMessageContext, ESPMode::ThreadSafe>(
Message,
TypeInfo,
Annotations,
nullptr,
Publisher->GetSenderAddress(),
TArray<FMessageAddress>(),
Scope,
EMessageFlags::None,
FDateTime::UtcNow() + Delay,
Expiration,
FTaskGraphInterface::Get().GetCurrentThreadIfKnown()
));
}
void FMessageBus::Register(const FMessageAddress& Address, const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Recipient)
{
UE_LOG(LogMessaging, Verbose, TEXT("Registering %s"), *Address.ToString());
Router->AddRecipient(Address, Recipient);
}
void FMessageBus::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,
const TSharedRef<IMessageSender, ESPMode::ThreadSafe>& Sender
)
{
UE_LOG(LogMessaging, Verbose, TEXT("Sending %s to %d recipients"), *TypeInfo->GetName(), Recipients.Num());
Router->RouteMessage(MakeShared<FMessageContext, ESPMode::ThreadSafe>(
Message,
TypeInfo,
Annotations,
Attachment,
Sender->GetSenderAddress(),
Recipients,
EMessageScope::Network,
Flags,
FDateTime::UtcNow() + Delay,
Expiration,
FTaskGraphInterface::Get().GetCurrentThreadIfKnown()
));
}
void FMessageBus::Shutdown()
{
if (RouterThread != nullptr)
{
ShutdownDelegate.Broadcast();
RouterThread->Kill(true);
delete RouterThread;
RouterThread = nullptr;
}
}
TSharedPtr<IMessageSubscription, ESPMode::ThreadSafe> FMessageBus::Subscribe(
const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber,
const FTopLevelAssetPath& MessageType,
const FMessageScopeRange& ScopeRange
)
{
if (!MessageType.IsNull())
{
if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeSubscription(Subscriber, MessageType))
{
UE_LOG(LogMessaging, Verbose, TEXT("Subscribing %s"), *Subscriber->GetDebugName().ToString());
TSharedRef<IMessageSubscription, ESPMode::ThreadSafe> Subscription = MakeShareable(new FMessageSubscription(Subscriber, MessageType, ScopeRange));
Router->AddSubscription(Subscription);
return Subscription;
}
}
return nullptr;
}
void FMessageBus::Unintercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FTopLevelAssetPath& MessageType)
{
if (!MessageType.IsNull())
{
UE_LOG(LogMessaging, Verbose, TEXT("Unintercepting %s"), *Interceptor->GetDebugName().ToString());
Router->RemoveInterceptor(Interceptor, MessageType);
}
}
void FMessageBus::Unregister(const FMessageAddress& Address)
{
UE_LOG(LogMessaging, Verbose, TEXT("Attempting to unregister %s"), *Address.ToString());
if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeUnregistration(Address))
{
UE_LOG(LogMessaging, Verbose, TEXT("Unregistered %s"), *Address.ToString());
Router->RemoveRecipient(Address);
}
}
void FMessageBus::Unsubscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FTopLevelAssetPath& MessageType)
{
if (!MessageType.IsNull())
{
if (!RecipientAuthorizer.IsValid() || RecipientAuthorizer->AuthorizeUnsubscription(Subscriber, MessageType))
{
UE_LOG(LogMessaging, Verbose, TEXT("Unsubscribing %s"), *Subscriber->GetDebugName().ToString());
Router->RemoveSubscription(Subscriber, MessageType);
}
}
}
void FMessageBus::AddNotificationListener(const TSharedRef<IBusListener, ESPMode::ThreadSafe>& Listener)
{
Router->AddNotificationListener(Listener);
}
void FMessageBus::RemoveNotificationListener(const TSharedRef<IBusListener, ESPMode::ThreadSafe>& Listener)
{
Router->RemoveNotificationListener(Listener);
}
const FString& FMessageBus::GetName() const
{
return Name;
}
// IMessageBus deprecated functions
void IMessageBus::Intercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FName& MessageType)
{
Intercept(Interceptor, UClass::TryConvertShortTypeNameToPathName<UStruct>(MessageType.ToString()));
}
TSharedPtr<IMessageSubscription, ESPMode::ThreadSafe> IMessageBus::Subscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FName& MessageType, const TRange<EMessageScope>& ScopeRange)
{
return Subscribe(Subscriber, UClass::TryConvertShortTypeNameToPathName<UStruct>(MessageType.ToString()), ScopeRange);
}
void IMessageBus::Unintercept(const TSharedRef<IMessageInterceptor, ESPMode::ThreadSafe>& Interceptor, const FName& MessageType)
{
Unintercept(Interceptor, UClass::TryConvertShortTypeNameToPathName<UStruct>(MessageType.ToString()));
}
void IMessageBus::Unsubscribe(const TSharedRef<IMessageReceiver, ESPMode::ThreadSafe>& Subscriber, const FName& MessageType)
{
Unsubscribe(Subscriber, UClass::TryConvertShortTypeNameToPathName<UStruct>(MessageType.ToString()));
}