public class SessionServices : ModuleRules
{
public SessionServices(ReadOnlyTargetRules Target) : base(Target)
{
PublicDependencyModuleNames.AddRange(
new string[] {
"Core",
});
PrivateDependencyModuleNames.AddRange(
new string[] {
"CoreUObject",
"EngineMessages",
"SessionMessages",
});
PrivateIncludePathModuleNames.AddRange(
new string[] {
"Messaging",
"MessagingCommon",
});
}
}
SessionService依赖SessionMessages
这个模块。用到了MessagingCommn
和Messaging
这连个模块内的头文件。
定义的接口
ISessionService
ISessionService表示一个会话的服务。
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
/**
* Interface for application session services.
*/
class ISessionService
{
public:
/**
* Checks whether the service is running.
*
* @return true if the service is running, false otherwise.
* @see Start, Stop
*/
virtual bool IsRunning() = 0;
/**
* Starts the service.
*
* @return true if the service was started, false otherwise.
* @see IsRunning, Stop
*/
virtual bool Start() = 0;
/**
* Stops the service.
*
* @see IsRunning, Start
*/
virtual void Stop() = 0;
public:
/** Virtual destructor. */
virtual ~ISessionService() { }
};
简单的三个方法:
- Run
- Stop
- IsRunning
加上一个必备的虚析构函数。
ISessionManager
ISessionManager中定义了如何管理这个Session的一些方法。
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ISessionInstanceInfo.h"
#include "ISessionInfo.h"
#include "SessionLogMessage.h"
/**
* Interface for the session manager.
*/
class ISessionManager
{
public:
/**
* Adds an owner whose sessions we are interested in
*
* @param InOwner Session owner we want to view sessions from
*/
virtual void AddOwner( const FString& InOwner ) = 0;
/**
* Gets the collection of currently selected engine instances.
*
* @return The selected instances.
*/
virtual const TArray<TSharedPtr<ISessionInstanceInfo>>& GetSelectedInstances() const = 0;
/**
* Get the selected session - as chosen in the session browser
*
* @return The session ID selected
*/
virtual const TSharedPtr<ISessionInfo>& GetSelectedSession() const = 0;
/**
* Gets the list of all discovered sessions.
*
* @param OutSessions Will hold the collection of sessions.
*/
virtual void GetSessions( TArray<TSharedPtr<ISessionInfo>>& OutSessions ) const = 0;
/**
* Checks whether the given instance is currently selected.
*
* @return true if the instance is selected, false otherwise.
*/
virtual bool IsInstanceSelected( const TSharedRef<ISessionInstanceInfo>& Instance ) const = 0;
/**
* Removes an owner whose sessions we are no longer interested in
*
* @param InOwner Session owner we want to remove
*/
virtual void RemoveOwner( const FString& InOwner ) = 0;
/**
* Selects the specified session.
*
* @param Session The session to the select (can be NULL to select none).
* @return true if the session was selected, false otherwise.
*/
virtual bool SelectSession( const TSharedPtr<ISessionInfo>& Session ) = 0;
/**
* Marks the specified item as selected or unselected.
*
* @param Instance The instance to mark.
* @param Selected Whether the instance should be selected (true) or unselected (false).
* @return true if the instance was selected, false otherwise.
*/
virtual bool SetInstanceSelected( const TSharedRef<ISessionInstanceInfo>& Instance, bool Selected ) = 0;
public:
/**
* Returns a delegate that is executed before a session is being selected.
*
* @return The delegate.
*/
DECLARE_EVENT_TwoParams(ISessionManager, FCanSelectSessionEvent, const TSharedPtr<ISessionInfo>& /*Session*/, bool& /*OutCanSelect*/)
virtual FCanSelectSessionEvent& OnCanSelectSession() = 0;
/**
* Returns a delegate that is executed when an instance changes its selection state.
*
* @return The delegate.
*/
DECLARE_EVENT_TwoParams(ISessionManager, FInstanceSelectionChangedEvent, const TSharedPtr<ISessionInstanceInfo>& /*Instance*/, bool /*Selected*/)
virtual FInstanceSelectionChangedEvent& OnInstanceSelectionChanged() = 0;
/**
* Returns a delegate that is executed when the selected session received a log message from one of its instances.
*
* @return The delegate.
*/
DECLARE_EVENT_ThreeParams(ISessionManager, FLogReceivedEvent, const TSharedRef<ISessionInfo>& /*OwnerSession*/, const TSharedRef<ISessionInstanceInfo>& /*SessionInstance*/, const TSharedRef<FSessionLogMessage>& /*LogMessage*/);
virtual FLogReceivedEvent& OnLogReceived() = 0;
/**
* Returns a delegate that is executed when the selected session changed.
*
* @return The delegate.
*/
DECLARE_EVENT_OneParam(ISessionManager, FSelectedSessionChangedEvent, const TSharedPtr<ISessionInfo>& /*SelectedSession*/)
virtual FSelectedSessionChangedEvent& OnSelectedSessionChanged() = 0;
/**
* Returns a delegate that is executed when the list of sessions has changed.
*
* @return The delegate.
*/
virtual FSimpleMulticastDelegate& OnSessionsUpdated() = 0;
/**
* Returns a delegate that is executed when a session instance is updated.
*
* @return The delegate.
*/
virtual FSimpleMulticastDelegate& OnSessionInstanceUpdated() = 0;
public:
/** Virtual destructor. */
virtual ~ISessionManager() { }
};
我们一个一个来分析:
- AddOwner,添加一个Session感兴趣的所有者。
- RemoveOwner,一出一个Session不再感兴趣的所有者。
- GetSelectedInstances,获取当前所选择的所有引擎实例集合。
- GetSelectedSession,获取选择的Session实例,也就是相当于在ui中点击选中的Session。
- GetSessions,获取所有已经发现的Session列表。
- IsInstanceSelected,检查当前是否选择了给定的实例。
- SelectSession,选择一个指定的Session
- SetInstanceSelected,设置一个指定的实例选中或者不选中。
接下来是事件相关:
DECLARE_EVENT_TwoParams(ISessionManager, FCanSelectSessionEvent, const TSharedPtr<ISessionInfo>& /*Session*/, bool& /*OutCanSelect*/)
virtual FCanSelectSessionEvent& OnCanSelectSession() = 0;
在选择一个Session开始时执行的委托。
DECLARE_EVENT_TwoParams(ISessionManager, FInstanceSelectionChangedEvent, const TSharedPtr<ISessionInstanceInfo>& /*Instance*/, bool /*Selected*/)
virtual FInstanceSelectionChangedEvent& OnInstanceSelectionChanged() = 0;
选择的实例改变后执行的委托。
DECLARE_EVENT_ThreeParams(ISessionManager, FLogReceivedEvent, const TSharedRef<ISessionInfo>& /*OwnerSession*/, const TSharedRef<ISessionInstanceInfo>& /*SessionInstance*/, const TSharedRef<FSessionLogMessage>& /*LogMessage*/);
virtual FLogReceivedEvent& OnLogReceived() = 0;
接收日志后执行的委托。
DECLARE_EVENT_OneParam(ISessionManager, FSelectedSessionChangedEvent, const TSharedPtr<ISessionInfo>& /*SelectedSession*/)
virtual FSelectedSessionChangedEvent& OnSelectedSessionChanged() = 0;
选择的Session改变后执行的委托。
virtual FSimpleMulticastDelegate& OnSessionsUpdated() = 0;
当Session更新后执行的委托。
virtual FSimpleMulticastDelegate& OnSessionInstanceUpdated() = 0;
当Session实例更新后执行的委托。
ISessionModule
这个接口仅仅简单包装了一下IModuleInterface
/**
* Interface for session core modules.
*/
class ISessionServicesModule
: public IModuleInterface
{
public:
/**
* Gets the session manager.
*
* @return The session manager.
* @see GetSessionService
*/
virtual TSharedPtr<ISessionManager> GetSessionManager() = 0;
/**
* Gets the session service.
*
* @return The session service.
* @see GetSessionManager
*/
virtual TSharedPtr<ISessionService> GetSessionService() = 0;
public:
/** Virtual destructor. */
virtual ~ISessionServicesModule() { }
};
其中两个方法:
- GetSessionManager,得到一个当前模块的SessionManager
- GetSessionService,得到一个当前模块的SessionService
实现
传递的消息
在模块SessionMessages SessionServiceMessage.h中
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Misc/Guid.h"
#include "SessionServiceMessages.generated.h"
/* Session discovery messages
*****************************************************************************/
/**
* Implements a message that is published to discover existing application sessions.
*/
USTRUCT()
struct FSessionServicePing
{
GENERATED_USTRUCT_BODY()
/** The name of the user who sent this ping. */
UPROPERTY(EditAnywhere, Category="Message")
FString UserName;
/** Default constructor. */
FSessionServicePing() { }
/** Creates and initializes a new instance. */
FSessionServicePing(const FString& InUserName)
: UserName(InUserName)
{ }
};
/**
* Implements a message that is published in response to FSessionServicePing.
*/
USTRUCT()
struct FSessionServicePong
{
GENERATED_USTRUCT_BODY()
/** Indicates whether the pinging user is authorized to interact with this session. */
UPROPERTY(EditAnywhere, Category="Message")
bool Authorized = true;
/** Holds the application's build date. */
UPROPERTY(EditAnywhere, Category="Message")
FString BuildDate;
/** Holds the name of the device that the application is running on. */
UPROPERTY(EditAnywhere, Category="Message")
FString DeviceName;
/** Holds the application's instance identifier. */
UPROPERTY(EditAnywhere, Category="Message")
FGuid InstanceId;
/** Holds the application's instance name. */
UPROPERTY(EditAnywhere, Category="Message")
FString InstanceName;
/** Holds the name of the platform that the application is running on. */
UPROPERTY(EditAnywhere, Category="Message")
FString PlatformName;
/** Holds the identifier of the session that the application belongs to. */
UPROPERTY(EditAnywhere, Category="Message")
FGuid SessionId;
/** Holds the user defined name of the session. */
UPROPERTY(EditAnywhere, Category="Message")
FString SessionName;
/** Holds the name of the user that started the session. */
UPROPERTY(EditAnywhere, Category="Message")
FString SessionOwner;
/** Indicates whether the application is the only one in that session. */
UPROPERTY(EditAnywhere, Category="Message")
bool Standalone = true;
};
/* Session status messages
*****************************************************************************/
/**
* Implements a message that contains a console log entry.
*/
USTRUCT()
struct FSessionServiceLog
{
GENERATED_USTRUCT_BODY()
/** Holds the log message category. */
UPROPERTY(EditAnywhere, Category="Message")
FName Category;
/** Holds the log message data. */
UPROPERTY(EditAnywhere, Category="Message")
FString Data;
/** Holds the application instance identifier. */
UPROPERTY(EditAnywhere, Category="Message")
FGuid InstanceId;
/** Holds the time in seconds since the application was started. */
UPROPERTY(EditAnywhere, Category="Message")
double TimeSeconds = 0.0;
/** Holds the log message's verbosity level. */
UPROPERTY(EditAnywhere, Category="Message")
uint8 Verbosity;
public:
/** Default constructor. */
FSessionServiceLog() : TimeSeconds(0.0), Verbosity(0) { }
/**
* Creates and initializes a new instance.
*/
FSessionServiceLog(const FName& InCategory, const FString& InData, const FGuid& InInstanceId, double InTimeSeconds, uint8 InVerbosity)
: Category(InCategory)
, Data(InData)
, InstanceId(InInstanceId)
, TimeSeconds(InTimeSeconds)
, Verbosity(InVerbosity)
{ }
};
/**
* Implements a message to subscribe to an application's console log.
*/
USTRUCT()
struct FSessionServiceLogSubscribe
{
GENERATED_USTRUCT_BODY()
};
/**
* Implements a message to unsubscribe from an application's console log.
*/
USTRUCT()
struct FSessionServiceLogUnsubscribe
{
GENERATED_USTRUCT_BODY()
};
我们可以看见有如下消息用于通信
- Ping
- Pong
- FSessionServiceLog,日志消息
- FSessionServiceLogUnsubscribe,表示取消订阅订阅日志。
FSessionService
SessionService.h
class FSessionService
: public FOutputDevice
, public ISessionService
FSessionService继承于FOutputDevice,ISessionService。
private:
/** Holds the list of log subscribers. */
TArray<FMessageAddress> LogSubscribers;
/** Holds a critical section for the log subscribers array. */
FCriticalSection LogSubscribersLock;
/** Holds a weak pointer to the message bus. */
TWeakPtr<IMessageBus, ESPMode::ThreadSafe> MessageBusPtr;
/** Holds the message endpoint. */
TSharedPtr<FMessageEndpoint, ESPMode::ThreadSafe> MessageEndpoint;
/** Set to true while in SendLog, used to avoid recursion */
bool IsInSendLog;
- LogSubscribers,一组订阅了日志的端点地址。
- MessageBusPtr,消息总线的弱引用。
- MessageEndpoint,service的消息端点。
构造函数:
FSessionService::FSessionService(const TSharedRef<IMessageBus, ESPMode::ThreadSafe>& InMessageBus)
: MessageBusPtr(InMessageBus)
{ }
使用一个const TSharedRef<IMessageBus, ESPMode::ThreadSafe>&
来构造MessageBusPtr。
析构函数:
FSessionService::~FSessionService()
{
Stop();
}
其中Stop的定义:
void FSessionService::Stop()
{
if (IsRunning())
{
GLog->RemoveOutputDevice(this);
MessageEndpoint.Reset();
}
}
如果IsRunning返回true,就重置MessageEndpoint。然后从GLog中移除自身。
IsRunning实现就是简单的检查MessageEndpoint是否合法:
virtual bool IsRunning() override
{
return MessageEndpoint.IsValid();
}
Start,也就是启动过程如下:
bool FSessionService::Start()
{
auto MessageBus = MessageBusPtr.Pin();
if (!MessageBus.IsValid())
{
return false;
}
// initialize messaging
MessageEndpoint = FMessageEndpoint::Builder("FSessionService", MessageBus.ToSharedRef())
.Handling<FSessionServiceLogSubscribe>(this, &FSessionService::HandleSessionLogSubscribeMessage)
.Handling<FSessionServiceLogUnsubscribe>(this, &FSessionService::HandleSessionLogUnsubscribeMessage)
.Handling<FSessionServicePing>(this, &FSessionService::HandleSessionPingMessage);
if (!MessageEndpoint.IsValid())
{
return false;
}
MessageEndpoint->Subscribe<>();
GLog->AddOutputDevice(this);
return true;
}
- 因为MessageBusPtr是一个弱引用,所以每次使用前都需要Pin一下,然后检查是否有效。
- 使用FMessageEndpoint::Builder构建一个MessageEndpoint并检查
- 使端点订阅FSessionServicePing这个消息。
- 向GLog中添加自身这个输出设备。
- 返回
对于MessageEndpoint构建过程中的Handling:
Handling<FSessionServiceLogSubscribe(this,&FSessionService::HandleSessionLogSubscribeMessage)
处理的是收到订阅日志消息后如何处理:
void FSessionService::HandleSessionLogSubscribeMessage(const FSessionServiceLogSubscribe& Message, const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context)
{
FScopeLock Lock(&LogSubscribersLock);
LogSubscribers.AddUnique(Context->GetSender());
}
- 上锁
- 向LogSubscriber中添加发送者。
处理取消订阅消息:
void FSessionService::HandleSessionLogUnsubscribeMessage(const FSessionServiceLogUnsubscribe& Message, const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context)
{
FScopeLock Lock(&LogSubscribersLock);
LogSubscribers.Remove(Context->GetSender());
}
- 上锁
- 然后删除发送者。
处理Ping消息:
void FSessionService::HandleSessionPingMessage(const FSessionServicePing& Message, const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context)
{
SendPong(Context, Message.UserName);
}
简单的会送一个Pong消息。
SendPong定义如下:
void FSessionService::SendPong(const TSharedRef<IMessageContext, ESPMode::ThreadSafe>& Context, const FString& UserName)
{
if (!MessageEndpoint.IsValid())
{
return;
}
FSessionServicePong* Message = new FSessionServicePong();
{
Message->Authorized = FApp::IsAuthorizedUser(UserName);
Message->BuildDate = FApp::GetBuildDate();
Message->DeviceName = FPlatformProcess::ComputerName();
Message->InstanceId = FApp::GetInstanceId();
Message->InstanceName = FApp::GetInstanceName();
Message->PlatformName = FPlatformProperties::PlatformName();
Message->SessionId = FApp::GetSessionId();
Message->SessionName = FApp::GetSessionName();
Message->SessionOwner = FApp::GetSessionOwner();
Message->Standalone = FApp::IsStandalone();
}
MessageEndpoint->Send(Message, Context->GetSender());
}
- 检查Endpoint是否合法
- 构建FSessionServicePong
- 使用Send方法发送构建出来的Pong信息。
FSessionServiceManager
第一部分的私有成员
/** The address of the automation controller to where we can forward any automation workers found. */
FGuid AutomationControllerAddress;
/** Holds the time at which the last ping was sent. */
FDateTime LastPingTime;
/** Holds a pointer to the message bus. */
TWeakPtr<IMessageBus, ESPMode::ThreadSafe> MessageBusPtr;
/** Holds the messaging endpoint. */
TSharedPtr<FMessageEndpoint, ESPMode::ThreadSafe> MessageEndpoint;
/** Holds the list of currently selected instances. */
TArray<TSharedPtr<ISessionInstanceInfo>> SelectedInstances;
/** Holds a reference to the currently selected session. */
TSharedPtr<ISessionInfo> SelectedSession;
/** Holds the collection of discovered sessions. */
//为每个发现的Session都分配了一个FGuid
TMap<FGuid, TSharedPtr<FSessionInfo>> Sessions;
每个变量的作用注释中已经说明。
第二部分的私有成员:
private:
/** Holds a delegate to be invoked before a session is selected. */
FCanSelectSessionEvent CanSelectSessionDelegate;
/** Holds a delegate to be invoked when an instance changes its selection state. */
FInstanceSelectionChangedEvent InstanceSelectionChangedDelegate;
/** Owner filter list. */
TArray<FString> FilteredOwners;
/** Holds a delegate to be invoked when the selected session received a log message. */
FLogReceivedEvent LogReceivedEvent;
/** Holds a delegate to be invoked when the selected session changed. */
FSelectedSessionChangedEvent SelectedSessionChangedEvent;
/** Holds a delegate to be invoked when the session list was updated. */
FSimpleMulticastDelegate SessionsUpdatedDelegate;
/** Holds a delegate to be invoked when a session instance is updated. */
FSimpleMulticastDelegate SessionInstanceUpdatedDelegate;
/** Holds a delegate to be invoked when the widget ticks. */
FDelegateHandle TickDelegateHandle;
分别对应接口中的事件。
发布Ping消息:
void FSessionManager::SendPing()
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FSessionmanager_SendPing);
if (MessageEndpoint.IsValid())
{
MessageEndpoint->Publish(new FEngineServicePing(), EMessageScope::Network);
MessageEndpoint->Publish(new FSessionServicePing(FPlatformProcess::UserName(false)), EMessageScope::Network);
}
LastPingTime = FDateTime::UtcNow();
}
每次发布一次Ping消息,都会更新LastPingTime
,以便周期性发布Ping:
bool FSessionManager::HandleTicker(float DeltaTime)
{
QUICK_SCOPE_CYCLE_COUNTER(STAT_FSessionmanager_HandleTicker);
FDateTime Now = FDateTime::UtcNow();
// @todo gmp: don't expire sessions for now
// FindExpiredSessions(Now);
if (Now >= LastPingTime + FTimespan::FromSeconds(SESSION_MANAGER_PING_INTERVAL))
{
SendPing();
}
return true;
}
构造函数:
FSessionManager::FSessionManager(const TSharedRef<IMessageBus, ESPMode::ThreadSafe>& InMessageBus)
: MessageBusPtr(InMessageBus)
{
// fill in the owner array
FString Filter;
// 命令解析
if (FParse::Value(FCommandLine::Get(), TEXT("SessionFilter="), Filter))
{
// Allow support for -SessionFilter=Filter1+Filter2+Filter3
int32 PlusIdx = Filter.Find(TEXT("+"), ESearchCase::CaseSensitive);
while (PlusIdx != INDEX_NONE)
{
FString Owner = Filter.Left(PlusIdx);
FilteredOwners.Add(Owner);
Filter.RightInline(Filter.Len() - (PlusIdx + 1), false);
PlusIdx = Filter.Find(TEXT("+"), ESearchCase::CaseSensitive);
}
FilteredOwners.Add(Filter);
}
// connect to message bus
MessageEndpoint = FMessageEndpoint::Builder("FSessionManager", InMessageBus)
.Handling<FEngineServicePong>(this, &FSessionManager::HandleEnginePongMessage)
.Handling<FSessionServicePong>(this, &FSessionManager::HandleSessionPongMessage);
// initialize ticker,注册HandleTicker到CoreTicker目的是为了周期性的发送Ping
TickDelegateHandle = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateRaw(this, &FSessionManager::HandleTicker), SESSION_MANAGER_PING_INTERVAL);
SendPing();
}
析构函数:
FSessionManager::~FSessionManager()
{
FTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);
}
将Ticker注销。
FSessionServiceModule
SessionServiceModule.cpp:
private:
/** Holds a weak pointer to the message bus. */
TWeakPtr<IMessageBus, ESPMode::ThreadSafe> MessageBusPtr;
/** Holds the session manager singleton. */
TSharedPtr<ISessionManager> SessionManager;
/** Holds the session service singleton. */
TSharedPtr<ISessionService> SessionService;
私有的三个成员:
- MessageBusPtr,消息总线的弱引用指针。
- SessionManager,一个ISessionManager的实例。
启动模块:
virtual void StartupModule() override
{
MessageBusPtr = IMessagingModule::Get().GetDefaultBus();
}
使用IMessagingModule::Get().GetDefaultBus();
获取一个系统默认的消息总线。
关闭模块:
virtual void ShutdownModule() override
{
SessionManager.Reset();
SessionService.Reset();
}
仅仅是重置两个指针。
SessionManager和SessionService使用惰性初始化的方式。
virtual TSharedPtr<ISessionManager> GetSessionManager() override
{
if (!SessionManager.IsValid() && MessageBusPtr.IsValid())
{
SessionManager = MakeShareable(new FSessionManager(MessageBusPtr.Pin().ToSharedRef()));
}
return SessionManager;
}
virtual TSharedPtr<ISessionService> GetSessionService() override
{
if (!SessionService.IsValid() && MessageBusPtr.IsValid())
{
SessionService = MakeShareable(new FSessionService(MessageBusPtr.Pin().ToSharedRef()));
}
return SessionService;
}
消息传递
简单的来说客户端和编辑器段做的内容大致如下:
客户端
- 每个游戏客户端持有一个
SessionService
,内包含一个MessageEndpoint
用于通信。 - 会处理日志订阅消息。
- 会处理日志取消订阅消息。
- 订阅Ping信息,处理Ping信息。然后SendPong。
- 记录了订阅日志消息的编辑器,向这些编辑器发送自己的日志。
编辑器
- 编辑器端持有一个
SessionManager
用于管理各个Session。 - 包含一个Endpoint端点用于通信。
- 会处理FEngineServicePong消息。
- 会处理FSessionServicePong消息。
- 周期性发布Ping消息,以便订阅了Ping消息的SessionService接收到。
注意下SessionManager会发送两种Ping,一种是自定义的FSessionSericePing,这种Ping由SessionService处理。
另一种是FEngineServicePing,这种Ping由引擎内部处理,Pong返回关于引擎的一些信息。
UI
在UI中,将使用到SessionInfo,SessionInstanceInfo,SessionManager中的其他方法和成员,比如点击一个正在主机上运行的游戏,就订阅这个游戏的日志,类似这种UI逻辑,都会在UI中实现。UI部分是编辑器特有的,Runtime并不会包含。
使用控件反射器可以定位到实现的源码。
SessionBrowser
private:
/** Holds an unfiltered list of available sessions. */
TArray<TSharedPtr<ISessionInfo>> AvailableSessions;
/** Holds the command bar. */
TSharedPtr<SSessionBrowserCommandBar> CommandBar;
/** Whether to ignore events from the session manager. */
bool IgnoreSessionManagerEvents;
/** Whether to ignore events from the session tree view. */
bool updatingTreeExpansion;
/** Maps session and instance GUIDs to existing tree items. */
TMap<FGuid, TSharedPtr<FSessionBrowserTreeItem>> ItemMap;
/** Holds a reference to the session manager. */
TSharedPtr<ISessionManager> SessionManager; //ISessionMessager的实例
/** Holds the filtered list of tree items. */
TArray<TSharedPtr<FSessionBrowserTreeItem>> SessionTreeItems;
/** Holds the session tree view. */
TSharedPtr<STreeView<TSharedPtr<FSessionBrowserTreeItem>>> SessionTreeView;
private:
/** The session tree item that holds this application's session. */
TSharedPtr<FSessionBrowserGroupTreeItem> AppGroupItem;
/** The session tree item that holds other user's sessions. */
TSharedPtr<FSessionBrowserGroupTreeItem> OtherGroupItem; //其他会话
/** The session tree item that holds the owner's remote sessions. */
TSharedPtr<FSessionBrowserGroupTreeItem> OwnerGroupItem; //我的会话
/** The session tree item that holds other user's standalone instances. */
TSharedPtr<FSessionBrowserGroupTreeItem> StandaloneGroupItem; //独立实例
/** This app's instance session */
TWeakPtr<FSessionBrowserTreeItem> ThisAppInstance; //此应用程序
/** True if we should set the default selection the next time the tree view if refreshed. */
bool bCanSetDefaultSelection;
UI部分的构建不是很重要,我们主要看SessionManager和UI的交互逻辑。
void SSessionBrowser::Construct( const FArguments& InArgs, TSharedRef<ISessionManager> InSessionManager )
{
IgnoreSessionManagerEvents = false;
updatingTreeExpansion = false;
bCanSetDefaultSelection = true;
SessionManager = InSessionManager;
构造函数中需要通过一个共享指针来传入SessionManager。构造SessionManager。
//TODO