Lyra学习002:LyraGameInstance.h 分析

LyraGameInstance.h 分析

1. 类声明与宏
UCLASS(MinimalAPI, Config = Game)
class ULyraGameInstance : public UCommonGameInstance
  • 分析: 该类继承自 UCommonGameInstance,这是 Lyra 项目对 UE 原生 UGameInstance 的扩展基类,提供了更多通用功能(如用户管理)。MinimalAPI 使得只有该类的主要函数被导出给其他模块,有助于编译时间。Config = Game 表示该类的配置属性(如果有)将存储在 DefaultGame.ini 等配置文件中。
2. 构造函数
UE_API ULyraGameInstance(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
  • 分析: 标准的构造函数。在 Lyra 项目中,它主要用于调用父类构造函数,并在 Init 函数中进行实际的初始化工作。
3. 成员函数:GetPrimaryPlayerController
UE_API ALyraPlayerController* GetPrimaryPlayerController() const;
  • 分析: 此函数用于获取游戏的主玩家控制器。在多人游戏中,通常指第一个本地玩家控制器。
  • 在 Lyra 项目中的应用: 任何需要获取主玩家控制器以执行输入、生成角色、更新用户界面等操作的代码都可能调用此函数。它是连接游戏实例和具体玩家操作的桥梁。
4. 成员函数:CanJoinRequestedSession
UE_API virtual bool CanJoinRequestedSession() const override;
  • 分析: 重写自父类,用于判断当前实例(或玩家)是否可以加入一个请求的游戏会话。
  • 在 Lyra 项目中的应用: 在尝试加入一个在线多人会话或服务器之前,框架会调用此函数进行检查。代码中的初始实现总是返回 true,但这为后续开发留下了扩展点,例如可以在这里检查玩家的网络连接状态、是否已登录、DLC 是否已加载等条件,以决定是否允许加入会话。
5. 成员函数:HandlerUserInitialized
UE_API virtual void HandlerUserInitialized(const UCommonUserInfo* UserInfo, bool bSuccess, FText Error, ECommonUserPrivilege RequestedPrivilege, ECommonUserOnlineContext OnlineContext) override;
  • 分析: 重写自父类,当用户(玩家)初始化过程(通常是登录过程)完成时,会回调此函数。
  • 在 Lyra 项目中的应用: 这是用户登录流程的关键节点。当玩家成功登录后(例如,通过了平台的认证),此函数会被调用。在 Lyra 中,它利用这个机会让对应的 ULyraLocalPlayer 从磁盘加载该玩家的个人设置(如音频设置、图形设置、控制设置等),确保每个用户的偏好都能在游戏开始时被正确应用。
6. 成员函数:ReceivedNetworkEncryptionToken
UE_API virtual void ReceivedNetworkEncryptionToken(const FString& EncryptionToken, const FOnEncryptionKeyResponse& Delegate) override;
  • 分析: 重写自父类。当作为客户端的游戏实例从服务器接收到一个加密令牌时,引擎会调用此函数。客户端需要根据此令牌提供相应的加密密钥,并通过调用传入的 Delegate 来响应。
  • 在 Lyra 项目中的应用: 这是 Lyra 实现网络通信加密的关键环节。它处理两种模式:
    • DTLS 加密: 使用证书和指纹进行更安全的加密连接,常用于测试或更高级的安全需求。
    • 简单调试加密: 使用硬编码的 DebugTestEncryptionKey。这是项目的主要演示模式,展示了如何建立加密连接,但绝对不应用于生产环境
7. 成员函数:ReceivedNetworkEncryptionAck
UE_API virtual void ReceivedNetworkEncryptionAck(const FOnEncryptionKeyResponse& Delegate) override;
  • 分析: 重写自父类。当服务器确认了客户端的加密设置后,客户端会收到一个 ACK(确认),此时引擎会调用此函数。客户端需要再次提供加密数据(对于 DTLS,这次需要提供服务器的证书指纹)以完成握手。
  • 在 Lyra 项目中的应用: 这是加密握手流程的第二步。它确保了客户端拥有验证服务器身份所需的信息(指纹),从而建立双向的、可信的加密通道。同样,它支持 DTLS 和简单调试两种模式。
8. 成员函数:Init
UE_API virtual void Init() override;
  • 分析: 重写自父类,在游戏实例创建后、游戏正式开始前被调用。
  • 在 Lyra 项目中的应用: 这是整个游戏初始化的核心入口。它做了几件关键事情:
    • 注册初始化状态: 通过 UGameFrameworkComponentManager 注册了从 SpawnedGameplayReady 等一系列初始化状态。这套状态机系统用于有序地管理游戏框架组件(如玩家状态、武器组件等)的初始化流程,确保依赖关系正确。
    • 初始化调试密钥: 准备了一个固定的、不安全的加密密钥 DebugTestEncryptionKey 用于测试。
    • 绑定会话旅行事件: 将 OnPreClientTravelToSession 函数绑定到会话子系统的 OnPreClientTravelEvent 上。
9. 成员函数:Shutdown
UE_API virtual void Shutdown() override;
  • 分析: 重写自父类,在游戏实例即将被销毁、游戏结束时调用。
  • 在 Lyra 项目中的应用: 执行清理工作,例如移除在 Init 中绑定的事件监听器,防止在游戏关闭过程中产生不必要的回调。
10. 成员函数:OnPreClientTravelToSession
UE_API void OnPreClientTravelToSession(FString& URL);
  • 分析: 这是一个自定义的回调函数,当客户端即将旅行(连接)到一个新的会话(服务器)时被调用。
  • 在 Lyra 项目中的应用: 它的主要作用是在启用加密测试 (Lyra::bTestEncryption) 时,向连接的 URL 中添加一个 EncryptionToken 查询参数。这个令牌(在 DTLS 模式下是玩家的唯一 ID,否则是固定值 “1”)会被发送到服务器,服务器端的 ReceivedNetworkEncryptionToken 函数会使用这个令牌来协商或查找对应的加密密钥。这是客户端主动发起加密握手的第一步。
11. 成员变量:DebugTestEncryptionKey
TArray<uint8> DebugTestEncryptionKey;
  • 分析: 一个字节数组,用于存储加密算法(如 AES256)所使用的密钥。
  • 在 Lyra 项目中的应用: 这是整个调试加密系统的核心。在 Init 中被初始化为一个固定的序列 [0, 1, 2, ..., 31]。在 ReceivedNetworkEncryptionTokenReceivedNetworkEncryptionAck 中,无论传入的令牌是什么,只要不使用 DTLS,最终都会将这个硬编码的密钥设置到响应中。这意味着客户端和服务器使用的是同一个固定的密钥,这非常不安全,但非常适合在开发阶段快速测试和验证网络加密管道的功能是否正常工作。

总结

ULyraGameInstance 在 Lyra 项目中扮演着游戏大脑的角色,其成员主要围绕以下几个核心应用:

  1. 游戏框架初始化: 通过 Init 和组件管理器,建立了一套严谨的初始化状态机,确保所有游戏系统按正确顺序启动。
  2. 用户生命周期管理: 通过 HandlerUserInitialized,将用户登录成功与加载个人设置关联起来,提供个性化的游戏体验。
  3. 网络会话与连接: 通过 CanJoinRequestedSessionOnPreClientTravelToSession 管理会话的加入和旅行过程。
  4. 网络通信安全(测试/演示)最重要的功能之一。提供了一套完整的、可配置的(通过控制台变量)网络加密演示方案。它同时实现了简单的静态密钥加密和更复杂的 DTLS 证书加密,为开发者提供了学习和集成安全网络通信的宝贵范例。所有加密相关的成员函数和变量都服务于这个目的。

这个类清晰地展示了如何在 UE5 中构建一个功能齐全、可扩展的多人游戏实例,特别是在处理用户状态和网络安全方面。

I DisplayPowerController[0]: Brightness [0.090349324] reason changing to: 'automatic', previous reason: 'screen_off'. 行 1219043: 11-10 16:26:20.366 1000 1667 1746 I DisplayPowerController[0]: Brightness [-1.0] reason changing to: 'screen_off', previous reason: 'automatic'. 行 1219044: 11-10 16:26:20.366 1000 1667 1746 I DisplayPowerController[0]: BrightnessEvent: brt=-1.0 (0.0%), nits= 2.0, lux=-1.0, reason=screen_off, strat=ScreenOffBrightnessStrategy, state=OFF, stateReason=DEFAULT_POLICY, policy=OFF, flags=, initBrt=0.09054119, rcmdBrt=NaN, preBrt=NaN, preLux=0.0, wasShortTermModelActive=false, autoBrightness=true (default), unclampedBrt=-1.0, hbmMax=0.49975574, hbmMode=off, thrmMax=1.0, rbcStrength=50, powerFactor=1.0, physDisp=内置屏幕(local:4627039422300187648), logicalId=0, slowChange=false, rampSpeed=0.0 行 1219214: 11-10 16:26:20.421 1002 3345 4100 I BtGatt.ScanManager: msg.what = MSG_SCREEN_OFF, msg.arg1 = None 行 1219216: 11-10 16:26:20.421 1002 3345 4100 D BtGatt.ScanManager: Scan mode update during screen off from SCAN_MODE_AMBIENT_DISCOVERY to SCAN_MODE_SCREEN_OFF_BALANCED 行 1219219: 11-10 16:26:20.422 1002 3345 4100 D BtGatt.ScanManager: Scan mode update during screen off from SCAN_MODE_AMBIENT_DISCOVERY to SCAN_MODE_SCREEN_OFF_BALANCED 行 1219674: 11-10 16:26:20.607 1000 2337 2463 D MiuiBubbleController: onReceive broadcast info:[intent.getSender() = android, action = android.intent.action.SCREEN_OFF] 行 1219728: 11-10 16:26:20.631 1000 3668 3668 I msguard : screen receiver:android.intent.action.SCREEN_OFF 行 1219811: 11-10 16:26:20.661 10152 2753 2753 I Launcher: mBroadcastReceiver onReceive: Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 } 行 1219902: 11-10 16:26:20.686 1002 3345 3345 D BtGatt.GattService: onReceive: android.intent.action.SCREEN_OFF 行 1219931: 11-10 16:26:20.706 1000 5217 5472 I TrafficManageService: onReceive: android.intent.action.SCREEN_OFF 行 1219933: 11-10 16:26:20.707 1002 3345 3884 D BluetoothAdapterService: onReceivedBroadcast android.intent.action.SCREEN_OFF 行 1219964: 11-10 16:26:20.719 1000 5217 5593 I BaseChargeProtect_Night: receiver ACTION_SCREEN_OFF 行 1219968: 11-10 16:26:20.723 1000 20978 20978 I ScreenReceiver: onReceive() called with: context = com.xiaomi.continuity.LiteContinuityApplication@b359d92, intent = Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 } 行 1219973: 11-10 16:26:20.726 1002 9759 9759 D MiuiFastConnectService_Plugin: onReceive(): action = android.intent.action.SCREEN_OFF 行 1219975: 11-10 16:26:20.727 1000 1667 1667 D HyperNotificationManagerService: BroadcastReceiver ACTION_SCREEN_OFF 行 1219996: 11-10 16:26:20.748 1000 20978 20978 I SystemMonitor: onReceive action:android.intent.action.SCREEN_OFF 行 1220023: 11-10 16:26:20.756 1002 9759 9759 D BluetoothHeadsetService: headset receviver android.intent.action.SCREEN_OFF 行 1220037: 11-10 16:26:20.761 1000 5217 5217 I VideoToolBoxService: onReceive: android.intent.action.SCREEN_OFF 行 1220075: 11-10 16:26:20.777 1000 1667 1667 D MiuiFboService: received the broadcast and intent.action : android.intent.action.SCREEN_OFF,intent.getStringExtra:null 行 1220076: 11-10 16:26:20.777 1000 1667 1667 I MiuiFboService: execute ACTION_SCREEN_OFF 行 1220084: 11-10 16:26:20.778 1000 20978 21071 W lyra-disc: DiscoveryPowerPolicy::IsAllowDiscovery:224 not allow, medium_type=2, work_when_screen_off=0, is_screen_on=0 行 1220180: 11-10 16:26:20.806 1000 20978 21071 W lyra-disc: DiscoveryPowerPolicy::IsAllowDiscovery:224 not allow, medium_type=20000, work_when_screen_off=0, is_screen_on=0 行 1220201: 11-10 16:26:20.812 1000 5217 5217 I PowerSaveService: onReceive: android.intent.action.SCREEN_OFF 行 1220282: 11-10 16:26:20.840 1000 2337 2337 I MiuiChargeController: dismissChargeAnimation: dismiss_for_screen_off 行 1220285: 11-10 16:26:20.840 1000 2337 2337 I NfcPhoneCaseController: dismissNfcAnimation reason: screen_off, showing: false 行 1220335: 11-10 16:26:20.855 1002 9759 9759 D MiuiBluetoothNotification: get receiver android.intent.action.SCREEN_OFF 行 1220346: 11-10 16:26:20.858 1000 2337 2337 I VolumePanelViewController_true: dismissH mShowing:false, reason:screen_off, isAnimating: false, needShowDialog=true, KeyAnimatingStream=-1, disableVolumeDialog=false 行 1220368: 11-10 16:26:20.866 1000 1667 1720 I SmartPower: com.google.android.gms.unstable/10148(4872): idle->background(2200ms) R(broadcast start Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 }) adj=800. 行 1220410: 11-10 16:26:20.907 1000 1667 1720 I SmartPower: com.google.android.inputmethod.latin/10181(7739): idle->background(17881ms) R(broadcast start Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 }) adj=100. 行 1220413: 11-10 16:26:20.909 1000 1667 1720 I SmartPower: com.xiaomi.aicr:cognitionService/10145(6885): idle->background(22833ms) R(broadcast start Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 }) adj=200. 行 1220419: 11-10 16:26:20.915 10181 7739 10537 I DeviceStatusMonitor: DeviceStatusMonitor.handleBroadcast():123 onReceive() : Action = android.intent.action.SCREEN_OFF 行 1220440: 11-10 16:26:20.934 1000 1667 1720 I SmartPower: com.miui.analytics/10172(28332): idle->background(30232ms) R(broadcast start Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 }) adj=100. 行 1220466: 11-10 16:26:20.954 10148 2451 5197 W NearbyDiscovery: FastPairHandler: skip handleStateEvent: eventType=SCREEN_OFF [CONTEXT service_id=265 ]是什么意思
11-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值