Files
UnrealEngine/Engine/Plugins/Animation/LiveLinkHub/Source/LiveLinkHubMessaging/Private/LiveLinkHubMessagingModule.cpp
2025-05-18 13:04:45 +08:00

163 lines
5.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "LiveLinkHubMessagingModule.h"
#include "CoreMinimal.h"
#include "LiveLinkHubConnectionManager.h"
#include "LiveLinkHubMessageBusSourceFactory.h"
#include "LiveLinkMessageBusSourceFactory.h"
#include "MessageEndpoint.h"
#include "MessageEndpointBuilder.h"
#include "Misc/ConfigCacheIni.h"
#include "Misc/ScopeLock.h"
#include "Modules/ModuleManager.h"
DEFINE_LOG_CATEGORY(LogLiveLinkHubMessaging);
namespace Internal
{
// Source: https://en.cppreference.com/w/cpp/utility/variant/visit
template<class... Ts>
struct TOverloaded : Ts...
{
using Ts::operator()...;
};
template<class... Ts> TOverloaded(Ts...) -> TOverloaded<Ts...>;
}
void FLiveLinkHubMessagingModule::StartupModule()
{
const bool bIsLiveLinkHubHost = GConfig->GetBoolOrDefault(
TEXT("LiveLink"), TEXT("bCreateLiveLinkHubInstance"), false, GEngineIni);
InstanceInfo.TopologyMode = bIsLiveLinkHubHost ? ELiveLinkTopologyMode::Hub : ELiveLinkTopologyMode::UnrealClient;
#if WITH_LIVELINK_DISCOVERY_MANAGER_THREAD
ConnectionManager = MakePimpl<FLiveLinkHubConnectionManager>(InstanceInfo.TopologyMode,
FLiveLinkHubConnectionManager::FOnGetTopologyMode::CreateRaw(this, &FLiveLinkHubMessagingModule::GetHostTopologyMode),
FLiveLinkHubConnectionManager::FOnGetInstanceId::CreateRaw(this, &FLiveLinkHubMessagingModule::GetInstanceId)
);
GameThreadEndpoint = FMessageEndpoint::Builder(TEXT("LiveLinkHubDiscoveryEndpoint"))
.Handling<FLiveLinkHubDiscoveryMessage>(this, &FLiveLinkHubMessagingModule::HandleDiscoveryMessage);
GameThreadEndpoint->Subscribe<FLiveLinkHubDisconnectMessage>();
GameThreadEndpoint->Subscribe<FLiveLinkHubDiscoveryMessage>();
#endif
SourceFilterDelegate = ILiveLinkModule::Get().RegisterMessageBusSourceFilter(FOnLiveLinkShouldDisplaySource::CreateRaw(this, &FLiveLinkHubMessagingModule::OnFilterMessageBusSource));
}
void FLiveLinkHubMessagingModule::ShutdownModule()
{
if (ILiveLinkModule* LiveLinkModule = FModuleManager::Get().GetModulePtr<ILiveLinkModule>("LiveLink"))
{
LiveLinkModule->UnregisterMessageBusSourceFilter(SourceFilterDelegate);
}
#if WITH_LIVELINK_DISCOVERY_MANAGER_THREAD
ConnectionManager.Reset();
#endif
}
void FLiveLinkHubMessagingModule::SetHostTopologyMode(ELiveLinkTopologyMode InMode)
{
FScopeLock Lock(&InstanceInfoLock);
InstanceInfo.TopologyMode = InMode;
}
FLiveLinkHubInstanceId FLiveLinkHubMessagingModule::GetInstanceId() const
{
FScopeLock Lock(&InstanceInfoLock);
return InstanceInfo.Id;
}
void FLiveLinkHubMessagingModule::SetInstanceId(const FLiveLinkHubInstanceId& Id)
{
FScopeLock Lock(&InstanceInfoLock);
InstanceInfo.Id = Id;
}
ELiveLinkTopologyMode FLiveLinkHubMessagingModule::GetHostTopologyMode() const
{
FScopeLock Lock(&InstanceInfoLock);
return InstanceInfo.TopologyMode;
}
bool FLiveLinkHubMessagingModule::OnFilterMessageBusSource(UClass* FactoryClass, TSharedPtr<struct FProviderPollResult, ESPMode::ThreadSafe> PollResult)
{
// Only display Hub/Spoke sources in "LiveLinkHub" section of the add source dropdown.
bool bValidTopologyMode = false;
if (FactoryClass == ULiveLinkHubMessageBusSourceFactory::StaticClass())
{
bValidTopologyMode = LiveLinkHubConnectionManager::GetPollResultTopologyMode(PollResult) == ELiveLinkTopologyMode::Hub || LiveLinkHubConnectionManager::GetPollResultTopologyMode(PollResult) == ELiveLinkTopologyMode::Spoke;
}
else if (FactoryClass == ULiveLinkMessageBusSourceFactory::StaticClass())
{
bValidTopologyMode = LiveLinkHubConnectionManager::GetPollResultTopologyMode(PollResult) != ELiveLinkTopologyMode::Hub;
}
return bValidTopologyMode && LiveLinkHubConnectionManager::ShouldAcceptConnectionFrom(InstanceInfo.TopologyMode, PollResult, InstanceInfo.Id);
}
void FLiveLinkHubMessagingModule::HandleDiscoveryMessage(const FLiveLinkHubDiscoveryMessage& Message, const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context)
{
// Before this annotation was added, LiveLinkHub would automatically be added, so we need to keep the previous behavior if we discovered an older LiveLinkHub instance.
ELiveLinkHubAutoConnectMode AutoConnectMode = ELiveLinkHubAutoConnectMode::Disabled;
if (const FString* AutoConnectModeAnnotation = Context->GetAnnotations().Find(FLiveLinkHubMessageAnnotation::AutoConnectModeAnnotation))
{
int64 AutoConnectModeValue = StaticEnum<ELiveLinkHubAutoConnectMode>()->GetValueByName(**AutoConnectModeAnnotation);
if (AutoConnectModeValue != INDEX_NONE)
{
AutoConnectMode = (ELiveLinkHubAutoConnectMode)AutoConnectModeValue;
}
}
bool bShouldConnect = UE::LiveLink::Messaging::CanReceiveFrom(InstanceInfo.TopologyMode, Message.Mode)
&& LiveLinkHubConnectionManager::CanConnectTo(Message.MachineName, *Context, InstanceInfo.Id);
if (bShouldConnect)
{
const double MachineTimeOffset = LiveLinkMessageBusHelper::CalculateProviderMachineOffset(Message.CreationTime, Context);
TSharedPtr<FLiveLinkHubMessageBusSource> LiveLinkSource = MakeShared<FLiveLinkHubMessageBusSource>(FText::FromString(Message.ProviderName), FText::FromString(Message.MachineName), Context->GetSender(), MachineTimeOffset, InstanceInfo.Id);
ILiveLinkClient* Client = &IModularFeatures::Get().GetModularFeature<ILiveLinkClient>(ILiveLinkClient::ModularFeatureName);
Client->AddSource(LiveLinkSource);
}
}
FLiveLinkHubInstanceId::FLiveLinkHubInstanceId(FGuid Guid)
{
Id.Set<FGuid>(Guid);
}
FLiveLinkHubInstanceId::FLiveLinkHubInstanceId(FStringView NamedId)
{
Id.Emplace<FString>(NamedId);
}
FString FLiveLinkHubInstanceId::ToString() const
{
auto Overload = Internal::TOverloaded{
[](FGuid InGuid) -> FString
{
TStringBuilder<20> LiveLinkHubName;
LiveLinkHubName << TEXT("Live Link Hub") << TEXT(" (") << *InGuid.ToString().Right(4).ToLower() << TEXT(")");
return LiveLinkHubName.ToString();
},
[](const FString& InId) -> FString
{
return InId;
}
};
return Visit(Overload, Id);
}
IMPLEMENT_MODULE(FLiveLinkHubMessagingModule, LiveLinkHubMessaging);