Files
UnrealEngine/Engine/Source/Runtime/Experimental/ChaosSolverEngine/Private/Chaos/ChaosVDRemoteSessionsManager.cpp
2025-05-18 13:04:45 +08:00

577 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Chaos/ChaosVDRemoteSessionsManager.h"
#include "ChaosVDRuntimeModule.h"
#include "IMessageBus.h"
#include "IMessagingModule.h"
#include "MessageEndpoint.h"
#include "MessageEndpointBuilder.h"
#include "ChaosVisualDebugger/ChaosVDOptionalDataChannel.h"
#include "Misc/App.h"
const FGuid FChaosVDRemoteSessionsManager::AllRemoteSessionsWrapperGUID = FGuid::NewGuid();
const FGuid FChaosVDRemoteSessionsManager::AllRemoteServersWrapperGUID = FGuid::NewGuid();
const FGuid FChaosVDRemoteSessionsManager::AllRemoteClientsWrapperGUID = FGuid::NewGuid();
const FGuid FChaosVDRemoteSessionsManager::AllSessionsWrapperGUID = FGuid::NewGuid();
const FGuid FChaosVDRemoteSessionsManager::CustomSessionsWrapperGUID = FGuid::NewGuid();
const FGuid FChaosVDRemoteSessionsManager::InvalidSessionGUID = FGuid();
const FString FChaosVDRemoteSessionsManager::LocalEditorSessionName = TEXT("Local Editor");
const FGuid FChaosVDRemoteSessionsManager::LocalEditorSessionID = IsController() ? FApp::GetInstanceId() : InvalidSessionGUID;
const FName FChaosVDRemoteSessionsManager::MessageBusEndPointName = FName("CVDSessionManagerEndPoint");
const FString FChaosVDRemoteSessionsManager::AllRemoteSessionsTargetName = TEXT("All Remote");
const FString FChaosVDRemoteSessionsManager::AllRemoteServersTargetName = TEXT("All Remote Servers");
const FString FChaosVDRemoteSessionsManager::AllRemoteClientsTargetName = TEXT("All Remote Clients");
const FString FChaosVDRemoteSessionsManager::AllSessionsTargetName = TEXT("All Sessions");
const FString FChaosVDRemoteSessionsManager::CustomSessionsTargetName = TEXT("Custom Selection");
DEFINE_LOG_CATEGORY(LogChaosVDRemoteSession)
bool FChaosVDSessionInfo::IsRecording() const
{
return LastKnownRecordingState.bIsRecording;
}
EChaosVDRecordingMode FChaosVDSessionInfo::GetRecordingMode() const
{
return LastKnownRecordingState.TraceDetails.Mode;
}
bool FChaosVDSessionInfo::IsConnected() const
{
return LastKnownRecordingState.TraceDetails.bIsConnected;
}
bool FChaosVDMultiSessionInfo::IsRecording() const
{
bool bIsRecording = false;
EnumerateInnerSessions([&bIsRecording](const TSharedRef<FChaosVDSessionInfo>& InSessionRef)
{
if (InSessionRef->IsRecording())
{
bIsRecording = true;
return false;
}
return true;
});
return bIsRecording;
}
EChaosVDRecordingMode FChaosVDMultiSessionInfo::GetRecordingMode() const
{
EChaosVDRecordingMode FirstInstanceRecordingMode = EChaosVDRecordingMode::Invalid;
EnumerateInnerSessions([&FirstInstanceRecordingMode](const TSharedRef<FChaosVDSessionInfo>& InSessionRef)
{
FirstInstanceRecordingMode = InSessionRef->GetRecordingMode();
return false;
});
return FirstInstanceRecordingMode;
}
bool FChaosVDMultiSessionInfo::IsConnected() const
{
bool bIsAnyConnected = false;
EnumerateInnerSessions([&bIsAnyConnected](const TSharedRef<FChaosVDSessionInfo>& InSessionRef)
{
if (InSessionRef->IsRecording())
{
bIsAnyConnected = true;
return false;
}
return true;
});
return bIsAnyConnected;
}
FChaosVDRemoteSessionsManager::FChaosVDRemoteSessionsManager()
{
}
constexpr bool FChaosVDRemoteSessionsManager::IsController()
{
#if WITH_EDITOR
return true;
#else
return false;
#endif
}
TWeakPtr<FChaosVDSessionInfo> FChaosVDRemoteSessionsManager::GetSessionInfo(FGuid Id)
{
if (TSharedPtr<FChaosVDSessionInfo>* FoundSessionPtrPtr = ActiveSessionsByInstanceId.Find(Id))
{
return *FoundSessionPtrPtr;
}
return nullptr;
}
TSharedPtr<FChaosVDSessionInfo> FChaosVDRemoteSessionsManager::CreatedWrapperSessionInfo(FGuid InstanceId, const FString& SessionName)
{
TSharedPtr<FChaosVDMultiSessionInfo> NewSessionInfo = MakeShared<FChaosVDMultiSessionInfo>();
NewSessionInfo->InstanceId = InstanceId;
NewSessionInfo->SessionName = SessionName;
return NewSessionInfo;
}
TSharedPtr<FMessageEndpoint> FChaosVDRemoteSessionsManager::CreateEndPoint(const TSharedRef<IMessageBus>& InMessageBus)
{
FMessageEndpointBuilder EndPointBuilder = FMessageEndpoint::Builder(MessageBusEndPointName, InMessageBus)
.Handling<FChaosVDSessionPing>(this, &FChaosVDRemoteSessionsManager::HandleSessionPingMessage)
.Handling<FChaosVDStartRecordingCommandMessage>(this, &FChaosVDRemoteSessionsManager::HandleRecordingStartCommandMessage)
.Handling<FChaosVDStopRecordingCommandMessage>(this, &FChaosVDRemoteSessionsManager::HandleRecordingStopCommandMessage)
.Handling<FChaosVDChannelStateChangeCommandMessage>(this, &FChaosVDRemoteSessionsManager::HandleChangeDataChannelStateCommandMessage)
.Handling<FChaosVDFullSessionInfoRequestMessage>(this, &FChaosVDRemoteSessionsManager::HandleFullSessionStateRequestMessage);
if (IsController())
{
EndPointBuilder.Handling<FChaosVDSessionPong>(this, &FChaosVDRemoteSessionsManager::HandleSessionPongMessage)
.Handling<FChaosVDRecordingStatusMessage>(this, &FChaosVDRemoteSessionsManager::HandleRecordingStatusUpdateMessage)
.Handling<FChaosVDFullSessionInfoResponseMessage>(this, &FChaosVDRemoteSessionsManager::HandleFullSessionStateResponseMessage)
.Handling<FChaosVDChannelStateChangeResponseMessage>(this, &FChaosVDRemoteSessionsManager::HandleChangeDataChannelStateResponseMessage)
.Handling<FChaosVDChannelStateChangeResponseMessage>(this, &FChaosVDRemoteSessionsManager::HandleChangeDataChannelStateResponseMessage);
}
return EndPointBuilder.Build();
}
void FChaosVDRemoteSessionsManager::Initialize()
{
TSharedPtr<IMessageBus> CVDMessageBus = IMessagingModule::Get().GetDefaultBus();
if (!ensure(CVDMessageBus))
{
return;
}
MessageBusPtr = CVDMessageBus;
MessageEndpoint = CreateEndPoint(CVDMessageBus.ToSharedRef());
if (!ensure(MessageEndpoint))
{
return;
}
if (IsController())
{
MessageEndpoint->Subscribe<FChaosVDSessionPong>();
MessageEndpoint->Subscribe<FChaosVDRecordingStatusMessage>();
MessageEndpoint->Subscribe<FChaosVDFullSessionInfoResponseMessage>();
MessageEndpoint->Subscribe<FChaosVDChannelStateChangeResponseMessage>();
}
MessageEndpoint->Subscribe<FChaosVDSessionPing>();
MessageEndpoint->Subscribe<FChaosVDStartRecordingCommandMessage>();
MessageEndpoint->Subscribe<FChaosVDStopRecordingCommandMessage>();
MessageEndpoint->Subscribe<FChaosVDChannelStateChangeCommandMessage>();
MessageEndpoint->Subscribe<FChaosVDFullSessionInfoRequestMessage>();
ActiveSessionsByInstanceId.Add(AllRemoteSessionsWrapperGUID, CreatedWrapperSessionInfo(AllRemoteSessionsWrapperGUID, AllRemoteSessionsTargetName));
ActiveSessionsByInstanceId.Add(AllRemoteServersWrapperGUID, CreatedWrapperSessionInfo(AllRemoteServersWrapperGUID, AllRemoteServersTargetName));
ActiveSessionsByInstanceId.Add(AllRemoteClientsWrapperGUID, CreatedWrapperSessionInfo(AllRemoteClientsWrapperGUID, AllRemoteClientsTargetName));
ActiveSessionsByInstanceId.Add(AllSessionsWrapperGUID, CreatedWrapperSessionInfo(AllSessionsWrapperGUID, AllSessionsTargetName));
ActiveSessionsByInstanceId.Add(CustomSessionsWrapperGUID, CreatedWrapperSessionInfo(CustomSessionsWrapperGUID, CustomSessionsTargetName));
constexpr float TickInterval = 1.0f;
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &FChaosVDRemoteSessionsManager::Tick), TickInterval);
}
void FChaosVDRemoteSessionsManager::Shutdown()
{
if (MessageEndpoint)
{
MessageEndpoint->Unsubscribe<FChaosVDSessionPong>();
MessageEndpoint->Unsubscribe<FChaosVDRecordingStatusMessage>();
MessageEndpoint->Unsubscribe<FChaosVDSessionPing>();
MessageEndpoint->Unsubscribe<FChaosVDStartRecordingCommandMessage>();
MessageEndpoint->Unsubscribe<FChaosVDStopRecordingCommandMessage>();
MessageEndpoint->Unsubscribe<FChaosVDChannelStateChangeCommandMessage>();
MessageEndpoint->Unsubscribe<FChaosVDFullSessionInfoRequestMessage>();
MessageEndpoint->Unsubscribe<FChaosVDFullSessionInfoResponseMessage>();
MessageEndpoint->Unsubscribe<FChaosVDChannelStateChangeResponseMessage>();
}
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
}
void FChaosVDRemoteSessionsManager::PublishRecordingStatusUpdate(const FChaosVDRecordingStatusMessage& UpdateMessage)
{
if (ensure(MessageEndpoint))
{
MessageEndpoint->Publish(FMessageEndpoint::MakeMessage<FChaosVDRecordingStatusMessage>(UpdateMessage), EMessageScope::Network);
}
}
void FChaosVDRemoteSessionsManager::PublishDataChannelStateChangeUpdate(const FChaosVDChannelStateChangeResponseMessage& InNewStateData)
{
if (ensure(MessageEndpoint))
{
MessageEndpoint->Publish(FMessageEndpoint::MakeMessage<FChaosVDChannelStateChangeResponseMessage>(InNewStateData), EMessageScope::Network);
}
}
void FChaosVDRemoteSessionsManager::SendStartRecordingCommand(const FMessageAddress& InDestinationAddress, const FChaosVDStartRecordingCommandMessage& RecordingStartCommandParams)
{
if (!MessageEndpoint)
{
UE_LOG(LogChaosVDRemoteSession, Error, TEXT("[%s] Failed to send command | Invalid endpoint."), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
MessageEndpoint->Send(
FMessageEndpoint::MakeMessage<FChaosVDStartRecordingCommandMessage>(RecordingStartCommandParams),
FChaosVDStartRecordingCommandMessage::StaticStruct(),
EMessageFlags::Reliable,
nullptr,
TArrayBuilder<FMessageAddress>().Add(InDestinationAddress),
FTimespan::Zero(),
FDateTime::MaxValue());
}
void FChaosVDRemoteSessionsManager::SendStopRecordingCommand(const FMessageAddress& InDestinationAddress)
{
if (!MessageEndpoint)
{
UE_LOG(LogChaosVDRemoteSession, Error, TEXT("[%s] Failed to send command | Invalid endpoint."), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
MessageEndpoint->Send(
FMessageEndpoint::MakeMessage<FChaosVDStopRecordingCommandMessage>(),
FChaosVDStopRecordingCommandMessage::StaticStruct(),
EMessageFlags::Reliable,
nullptr,
TArrayBuilder<FMessageAddress>().Add(InDestinationAddress),
FTimespan::Zero(),
FDateTime::MaxValue());
}
void FChaosVDRemoteSessionsManager::SendDataChannelStateChangeCommand(const FMessageAddress& InDestinationAddress,const FChaosVDChannelStateChangeCommandMessage& InNewStateData)
{
if (!MessageEndpoint)
{
UE_LOG(LogChaosVDRemoteSession, Error, TEXT("[%s] Failed to send command | Invalid endpoint."), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
MessageEndpoint->Send(
FMessageEndpoint::MakeMessage<FChaosVDChannelStateChangeCommandMessage>(InNewStateData),
FChaosVDChannelStateChangeCommandMessage::StaticStruct(),
EMessageFlags::Reliable,
nullptr,
TArrayBuilder<FMessageAddress>().Add(InDestinationAddress),
FTimespan::Zero(),
FDateTime::MaxValue());
}
void FChaosVDRemoteSessionsManager::SendFullSessionStateRequestCommand(const FMessageAddress& InDestinationAddress)
{
if (!MessageEndpoint)
{
UE_LOG(LogChaosVDRemoteSession, Error, TEXT("[%s] Failed to send command | Invalid endpoint."), ANSI_TO_TCHAR(__FUNCTION__));
return;
}
MessageEndpoint->Send(
FMessageEndpoint::MakeMessage<FChaosVDFullSessionInfoRequestMessage>(),
FChaosVDFullSessionInfoRequestMessage::StaticStruct(),
EMessageFlags::Reliable,
nullptr,
TArrayBuilder<FMessageAddress>().Add(InDestinationAddress),
FTimespan::Zero(),
FDateTime::MaxValue());
}
bool FChaosVDRemoteSessionsManager::Tick(float DeltaTime)
{
if (IsController())
{
SendPing();
RemoveExpiredSessions();
}
return true;
}
void FChaosVDRemoteSessionsManager::SendPing()
{
if (ensure(MessageEndpoint))
{
if (FChaosVDSessionPing* SessionPingData = FMessageEndpoint::MakeMessage<FChaosVDSessionPing>())
{
SessionPingData->ControllerInstanceId = FApp::GetInstanceId();
MessageEndpoint->Publish(SessionPingData, EMessageScope::Network);
}
}
}
void FChaosVDRemoteSessionsManager::SendPong(const FChaosVDSessionPing& InMessage)
{
if (!ensure(MessageEndpoint))
{
return;
}
if (FChaosVDSessionPong* PongMessage = FMessageEndpoint::MakeMessage<FChaosVDSessionPong>())
{
PongMessage->InstanceId = FApp::GetInstanceId();
PongMessage->SessionId = FApp::GetSessionId();
PongMessage->BuildTargetType = static_cast<uint8>(FApp::GetBuildTargetType());
if (InMessage.ControllerInstanceId == PongMessage->InstanceId)
{
PongMessage->SessionName = LocalEditorSessionName;
}
else
{
FString AppSessionName = FApp::GetSessionName();
PongMessage->SessionName = AppSessionName == TEXT("None") || AppSessionName.IsEmpty() ? FString::Format(TEXT("{0} {1} {2}"), { FApp::GetProjectName(), FString(LexToString(FApp::GetBuildTargetType())), FString::FromInt(FPlatformProcess::GetCurrentProcessId()) }) : AppSessionName;
}
MessageEndpoint->Publish(PongMessage, EMessageScope::Network);
}
}
void FChaosVDRemoteSessionsManager::RegisterSessionInMultiSessionWrapper(const TSharedRef<FChaosVDSessionInfo>& InSessionInfoRef)
{
if (InSessionInfoRef->SessionName != LocalEditorSessionName )
{
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllRemoteSessionsWrapperGUID))->InnerSessionsByInstanceID.Emplace(InSessionInfoRef->InstanceId, InSessionInfoRef);
if (InSessionInfoRef->BuildTargetType == EBuildTargetType::Server)
{
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllRemoteServersWrapperGUID))->InnerSessionsByInstanceID.Emplace(InSessionInfoRef->InstanceId, InSessionInfoRef);
}
else
{
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllRemoteClientsWrapperGUID))->InnerSessionsByInstanceID.Emplace(InSessionInfoRef->InstanceId, InSessionInfoRef);
}
}
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllSessionsWrapperGUID))->InnerSessionsByInstanceID.Emplace(InSessionInfoRef->InstanceId, InSessionInfoRef);
}
void FChaosVDRemoteSessionsManager::DeRegisterSessionInMultiSessionWrapper(const TSharedRef<FChaosVDSessionInfo>& InSessionInfoRef)
{
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllRemoteSessionsWrapperGUID))->InnerSessionsByInstanceID.Remove(InSessionInfoRef->InstanceId);
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllSessionsWrapperGUID))->InnerSessionsByInstanceID.Remove(InSessionInfoRef->InstanceId);
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllRemoteServersWrapperGUID))->InnerSessionsByInstanceID.Remove(InSessionInfoRef->InstanceId);
StaticCastSharedPtr<FChaosVDMultiSessionInfo>(ActiveSessionsByInstanceId.FindChecked(AllRemoteClientsWrapperGUID))->InnerSessionsByInstanceID.Remove(InSessionInfoRef->InstanceId);
}
void FChaosVDRemoteSessionsManager::HandleSessionPongMessage(const FChaosVDSessionPong& InMessage, const TSharedRef<IMessageContext>& InContext)
{
TSharedPtr<FChaosVDSessionInfo>& SessionInfoPtr = ActiveSessionsByInstanceId.FindOrAdd(InMessage.InstanceId);
if (!SessionInfoPtr)
{
SessionInfoPtr = MakeShared<FChaosVDSessionInfo>();
SessionInfoPtr->Address = InContext->GetSender();
SessionInfoPtr->InstanceId = InMessage.InstanceId;
SessionInfoPtr->SessionName = InMessage.SessionName;
SessionInfoPtr->BuildTargetType = static_cast<EBuildTargetType>(InMessage.BuildTargetType);
RegisterSessionInMultiSessionWrapper(SessionInfoPtr.ToSharedRef());
// This is the first time we see this session, so we need to request the rest of its state so we can properly populate the UI
SendFullSessionStateRequestCommand(SessionInfoPtr->Address);
}
SessionInfoPtr->LastPingTime = FDateTime::UtcNow();
PendingRecordingStatusMessages.RemoveAndCopyValue(InMessage.InstanceId, SessionInfoPtr->LastKnownRecordingState);
SessionsUpdatedDelegate.Broadcast();
}
void FChaosVDRemoteSessionsManager::HandleSessionPingMessage(const FChaosVDSessionPing& InMessage, const TSharedRef<IMessageContext>& InContext)
{
SendPong(InMessage);
}
void FChaosVDRemoteSessionsManager::HandleRecordingStatusUpdateMessage(const FChaosVDRecordingStatusMessage& Message, const TSharedRef<IMessageContext>& InContext)
{
if (TSharedPtr<FChaosVDSessionInfo>* SessionInfoPtrPtr = ActiveSessionsByInstanceId.Find(Message.InstanceId))
{
TSharedPtr<FChaosVDSessionInfo>& SessionInfoPtr = *SessionInfoPtrPtr;
check(SessionInfoPtr);
if (SessionInfoPtr->LastKnownRecordingState.bIsRecording != Message.bIsRecording)
{
if (Message.bIsRecording)
{
RecordingStartedDelegate.Broadcast(SessionInfoPtr);
}
else
{
RecordingStoppedDelegate.Broadcast(SessionInfoPtr);
}
}
SessionInfoPtr->LastKnownRecordingState = Message;
}
else
{
PendingRecordingStatusMessages.FindOrAdd(Message.InstanceId) = Message;
}
}
void FChaosVDRemoteSessionsManager::HandleRecordingStartCommandMessage(const FChaosVDStartRecordingCommandMessage& InMessage, const TSharedRef<IMessageContext>& InContext)
{
#if WITH_CHAOS_VISUAL_DEBUGGER
UE_AUTORTFM_ONCOMMIT(InMessage)
{
TArray<FString> RecordingParams;
if (InMessage.RecordingMode == EChaosVDRecordingMode::Live)
{
RecordingParams.Add(TEXT("Server"));
if (!InMessage.Target.IsEmpty())
{
RecordingParams.Add(InMessage.Target);
}
}
else if (InMessage.RecordingMode == EChaosVDRecordingMode::File)
{
RecordingParams.Add(TEXT("File"));
}
FChaosVDRuntimeModule::Get().StartRecording(RecordingParams);
};
#endif
}
void FChaosVDRemoteSessionsManager::HandleRecordingStopCommandMessage(const FChaosVDStopRecordingCommandMessage& InMessage, const TSharedRef<IMessageContext>& InContext)
{
#if WITH_CHAOS_VISUAL_DEBUGGER
UE_AUTORTFM_ONCOMMIT()
{
FChaosVDRuntimeModule::Get().StopRecording();
};
#endif
}
void FChaosVDRemoteSessionsManager::HandleChangeDataChannelStateCommandMessage(const FChaosVDChannelStateChangeCommandMessage& InMessage, const TSharedRef<IMessageContext>& InContext)
{
#if WITH_CHAOS_VISUAL_DEBUGGER
UE_AUTORTFM_ONCOMMIT(InMessage)
{
using namespace Chaos::VisualDebugger;
if (TSharedPtr<FChaosVDOptionalDataChannel> ChannelInstance = FChaosVDDataChannelsManager::Get().GetChannelById(FName(InMessage.NewState.ChannelName)))
{
ChannelInstance->SetChannelEnabled(InMessage.NewState.bIsEnabled);
}
};
#endif
}
void FChaosVDRemoteSessionsManager::HandleChangeDataChannelStateResponseMessage(const FChaosVDChannelStateChangeResponseMessage& InMessage, const TSharedRef<IMessageContext>& InContext)
{
if (TSharedPtr<FChaosVDSessionInfo>* SessionInfoPtrPtr = ActiveSessionsByInstanceId.Find(InMessage.InstanceID))
{
if (TSharedPtr<FChaosVDSessionInfo>& SessionInfoPtr = *SessionInfoPtrPtr)
{
if (FChaosVDDataChannelState* FoundChannelState = SessionInfoPtr->DataChannelsStatesByName.Find(InMessage.NewState.ChannelName))
{
*FoundChannelState = InMessage.NewState;
}
}
}
}
void FChaosVDRemoteSessionsManager::HandleFullSessionStateRequestMessage(const FChaosVDFullSessionInfoRequestMessage& InMessage, const TSharedRef<IMessageContext>& InContext)
{
if (!ensure(MessageEndpoint))
{
return;
}
if (FChaosVDFullSessionInfoResponseMessage* FullSessionStateResponse = FMessageEndpoint::MakeMessage<FChaosVDFullSessionInfoResponseMessage>())
{
FullSessionStateResponse->InstanceId = FApp::GetInstanceId();
#if WITH_CHAOS_VISUAL_DEBUGGER
FullSessionStateResponse->bIsRecording = FChaosVDRuntimeModule::Get().IsRecording();
using namespace Chaos::VisualDebugger;
FChaosVDDataChannelsManager::Get().EnumerateChannels([&FullSessionStateResponse](const TSharedRef<FChaosVDOptionalDataChannel>& Channel)
{
FChaosVDChannelStateChangeCommandMessage DataChannelStateMessage = {Channel->GetId().ToString(), Channel->IsChannelEnabled(), Channel->CanChangeEnabledState() };
FullSessionStateResponse->DataChannelsStates.Emplace(DataChannelStateMessage.NewState);
return true;
});
#endif
MessageEndpoint->Send(
FullSessionStateResponse,
FChaosVDFullSessionInfoResponseMessage::StaticStruct(),
EMessageFlags::Reliable,
nullptr,
TArrayBuilder<FMessageAddress>().Add(InContext->GetSender()),
FTimespan::Zero(),
FDateTime::MaxValue());
}
}
void FChaosVDRemoteSessionsManager::HandleFullSessionStateResponseMessage(const FChaosVDFullSessionInfoResponseMessage& InMessage, const TSharedRef<IMessageContext>& InContext)
{
if (TSharedPtr<FChaosVDSessionInfo>* SessionInfoPtrPtr = ActiveSessionsByInstanceId.Find(InMessage.InstanceId))
{
if (TSharedPtr<FChaosVDSessionInfo>& SessionInfoPtr = *SessionInfoPtrPtr)
{
SessionInfoPtr->LastKnownRecordingState.bIsRecording = InMessage.bIsRecording;
for (const FChaosVDDataChannelState& ChannelState : InMessage.DataChannelsStates)
{
SessionInfoPtr->DataChannelsStatesByName.Emplace(ChannelState.ChannelName, ChannelState);
}
}
}
}
void FChaosVDRemoteSessionsManager::RemoveExpiredSessions()
{
bool bAnySessionRemoved = false;
FDateTime CurrentTime = FDateTime::UtcNow();
for (TMap<FGuid, TSharedPtr<FChaosVDSessionInfo>>::TIterator RemoveIterator = ActiveSessionsByInstanceId.CreateIterator(); RemoveIterator; ++RemoveIterator)
{
TSharedPtr<FChaosVDSessionInfo>& SessionInfoPtr = RemoveIterator.Value();
if (!SessionInfoPtr)
{
RemoveIterator.RemoveCurrent();
bAnySessionRemoved = true;
continue;
}
if (!EnumHasAnyFlags(SessionInfoPtr->GetSessionTypeAttributes(), EChaosVDRemoteSessionAttributes::CanExpire))
{
continue;
}
FTimespan ElapsedTime = CurrentTime - SessionInfoPtr->LastPingTime;
// A session goes into busy state if we are attempting to issue a command that might stall the target, currently that only happens on recording start commands of complex maps
// In these cases, we need to allow more time between pings. If a recording command failed, it is expected the state to be changed to Ready again
const float MaxAllowedTimeBetweenPings = SessionInfoPtr->ReadyState == EChaosVDRemoteSessionReadyState::Busy ? 3.0f : 60.0f;
if (ElapsedTime > FTimespan::FromSeconds(MaxAllowedTimeBetweenPings))
{
DeRegisterSessionInMultiSessionWrapper(SessionInfoPtr.ToSharedRef());
RemoveIterator.RemoveCurrent();
bAnySessionRemoved = true;
}
}
if (bAnySessionRemoved)
{
SessionsUpdatedDelegate.Broadcast();
}
}