news 2026/3/24 17:09:15

LyraStarterGame_5.6 Experience系统加载流程详细实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LyraStarterGame_5.6 Experience系统加载流程详细实现

1. 加载流程概述

Lyra的Experience系统采用异步加载模式,确保游戏在加载过程中保持响应性。完整的加载流程包含以下状态转换:

Unloaded → Loading → LoadingGameFeatures → ExecutingActions → Loaded

2. 详细流程实现

2.1 设置当前经验

voidULyraExperienceManagerComponent::SetCurrentExperience(FPrimaryAssetId ExperienceId){ULyraAssetManager&AssetManager=ULyraAssetManager::Get();FSoftObjectPath AssetPath=AssetManager.GetPrimaryAssetPath(ExperienceId);TSubclassOf<ULyraExperienceDefinition>AssetClass=Cast<UClass>(AssetPath.TryLoad());check(AssetClass);constULyraExperienceDefinition*Experience=GetDefault<ULyraExperienceDefinition>(AssetClass);check(Experience!=nullptr);check(CurrentExperience==nullptr);CurrentExperience=Experience;StartExperienceLoad();}

关键实现点:

  • 通过ULyraAssetManager获取经验资源路径
  • 尝试加载资源类并转换为ULyraExperienceDefinition类型
  • 验证经验有效性并设置为当前经验
  • 调用StartExperienceLoad()开始加载流程

2.2 开始经验加载

voidULyraExperienceManagerComponent::StartExperienceLoad(){check(CurrentExperience!=nullptr);check(LoadState==ELyraExperienceLoadState::Unloaded);UE_LOG(LogLyraExperience,Log,TEXT("EXPERIENCE: StartExperienceLoad(CurrentExperience = %s, %s)"),*CurrentExperience->GetPrimaryAssetId().ToString(),*GetClientServerContextString(this));LoadState=ELyraExperienceLoadState::Loading;ULyraAssetManager&AssetManager=ULyraAssetManager::Get();TSet<FPrimaryAssetId>BundleAssetList;TSet<FSoftObjectPath>RawAssetList;BundleAssetList.Add(CurrentExperience->GetPrimaryAssetId());for(constTObjectPtr<ULyraExperienceActionSet>&ActionSet:CurrentExperience->ActionSets){if(ActionSet!=nullptr){BundleAssetList.Add(ActionSet->GetPrimaryAssetId());}}TArray<FName>BundlesToLoad;BundlesToLoad.Add(FLyraBundles::Equipped);constENetMode OwnerNetMode=GetOwner()->GetNetMode();constboolbLoadClient=GIsEditor||(OwnerNetMode!=NM_DedicatedServer);constboolbLoadServer=GIsEditor||(OwnerNetMode!=NM_Client);if(bLoadClient)BundlesToLoad.Add(UGameFeaturesSubsystemSettings::LoadStateClient);if(bLoadServer)BundlesToLoad.Add(UGameFeaturesSubsystemSettings::LoadStateServer);TSharedPtr<FStreamableHandle>BundleLoadHandle=nullptr;if(BundleAssetList.Num()>0){BundleLoadHandle=AssetManager.ChangeBundleStateForPrimaryAssets(BundleAssetList.Array(),BundlesToLoad,{},false,FStreamableDelegate(),FStreamableManager::AsyncLoadHighPriority);}TSharedPtr<FStreamableHandle>RawLoadHandle=nullptr;if(RawAssetList.Num()>0){RawLoadHandle=AssetManager.LoadAssetList(RawAssetList.Array(),FStreamableDelegate(),FStreamableManager::AsyncLoadHighPriority,TEXT("StartExperienceLoad()"));}TSharedPtr<FStreamableHandle>Handle=nullptr;if(BundleLoadHandle.IsValid()&&RawLoadHandle.IsValid()){Handle=AssetManager.GetStreamableManager().CreateCombinedHandle({BundleLoadHandle,RawLoadHandle});}else{Handle=BundleLoadHandle.IsValid()?BundleLoadHandle:RawLoadHandle;}FStreamableDelegate OnAssetsLoadedDelegate=FStreamableDelegate::CreateUObject(this,&ThisClass::OnExperienceLoadComplete);if(!Handle.IsValid()||Handle->HasLoadCompleted()){FStreamableHandle::ExecuteDelegate(OnAssetsLoadedDelegate);}else{Handle->BindCompleteDelegate(OnAssetsLoadedDelegate);Handle->BindCancelDelegate(FStreamableDelegate::CreateLambda([OnAssetsLoadedDelegate](){OnAssetsLoadedDelegate.ExecuteIfBound();}));}TSet<FPrimaryAssetId>PreloadAssetList;if(PreloadAssetList.Num()>0){AssetManager.ChangeBundleStateForPrimaryAssets(PreloadAssetList.Array(),BundlesToLoad,{});}}

关键实现点:

  • 验证当前经验有效性和加载状态
  • 记录加载日志,包含经验ID和客户端/服务器上下文
  • 转换状态为ELyraExperienceLoadState::Loading
  • 构建要加载的资源列表,包括经验定义和相关动作集
  • 根据网络模式(客户端/服务器/编辑器)确定要加载的资源包
  • 使用FStreamableHandle进行异步资源加载
  • 支持合并多个加载请求,提高效率
  • 绑定资源加载完成回调
  • 支持预加载额外资源(当前留空)

2.3 经验资源加载完成

voidULyraExperienceManagerComponent::OnExperienceLoadComplete(){check(LoadState==ELyraExperienceLoadState::Loading);check(CurrentExperience!=nullptr);UE_LOG(LogLyraExperience,Log,TEXT("EXPERIENCE: OnExperienceLoadComplete(CurrentExperience = %s, %s)"),*CurrentExperience->GetPrimaryAssetId().ToString(),*GetClientServerContextString(this));GameFeaturePluginURLs.Reset();autoCollectGameFeaturePluginURLs=[This=this](constUPrimaryDataAsset*Context,constTArray<FString>&FeaturePluginList){for(constFString&PluginName:FeaturePluginList){FString PluginURL;if(UGameFeaturesSubsystem::Get().GetPluginURLByName(PluginName,/*out*/PluginURL)){This->GameFeaturePluginURLs.AddUnique(PluginURL);}else{ensureMsgf(false,TEXT("OnExperienceLoadComplete failed to find plugin URL from PluginName %s for experience %s - fix data, ignoring for this run"),*PluginName,*Context->GetPrimaryAssetId().ToString());}}};CollectGameFeaturePluginURLs(CurrentExperience,CurrentExperience->GameFeaturesToEnable);for(constTObjectPtr<ULyraExperienceActionSet>&ActionSet:CurrentExperience->ActionSets){if(ActionSet!=nullptr){CollectGameFeaturePluginURLs(ActionSet,ActionSet->GameFeaturesToEnable);}}NumGameFeaturePluginsLoading=GameFeaturePluginURLs.Num();if(NumGameFeaturePluginsLoading>0){LoadState=ELyraExperienceLoadState::LoadingGameFeatures;for(constFString&PluginURL:GameFeaturePluginURLs){ULyraExperienceManager::NotifyOfPluginActivation(PluginURL);UGameFeaturesSubsystem::Get().LoadAndActivateGameFeaturePlugin(PluginURL,FGameFeaturePluginLoadComplete::CreateUObject(this,&ThisClass::OnGameFeaturePluginLoadComplete));}}else{OnExperienceFullLoadCompleted();}}

关键实现点:

  • 验证加载状态和当前经验有效性
  • 记录资源加载完成日志
  • 收集游戏特性插件URL的Lambda函数
  • 从经验定义和动作集中收集需要加载的游戏特性插件
  • 转换状态为ELyraExperienceLoadState::LoadingGameFeatures
  • 异步加载并激活游戏特性插件
  • 支持无插件情况下直接完成加载

2.4 游戏特性插件加载完成

voidULyraExperienceManagerComponent::OnGameFeaturePluginLoadComplete(constUE::GameFeatures::FResult&Result){NumGameFeaturePluginsLoading--;if(NumGameFeaturePluginsLoading==0){OnExperienceFullLoadCompleted();}}

关键实现点:

  • 递减正在加载的插件计数
  • 当所有插件加载完成后,调用最终完成函数

2.5 经验完全加载完成

voidULyraExperienceManagerComponent::OnExperienceFullLoadCompleted(){check(LoadState!=ELyraExperienceLoadState::Loaded);if(LoadState!=ELyraExperienceLoadState::LoadingChaosTestingDelay){constfloatDelaySecs=LyraConsoleVariables::GetExperienceLoadDelayDuration();if(DelaySecs>0.0f){FTimerHandle DummyHandle;LoadState=ELyraExperienceLoadState::LoadingChaosTestingDelay;GetWorld()->GetTimerManager().SetTimer(DummyHandle,this,&ThisClass::OnExperienceFullLoadCompleted,DelaySecs,/*bLooping=*/false);return;}}LoadState=ELyraExperienceLoadState::ExecutingActions;FGameFeatureActivatingContext Context;constFWorldContext*ExistingWorldContext=GEngine->GetWorldContextFromWorld(GetWorld());if(ExistingWorldContext){Context.SetRequiredWorldContextHandle(ExistingWorldContext->ContextHandle);}autoActivateListOfActions=[&Context](constTArray<UGameFeatureAction*>&ActionList){for(UGameFeatureAction*Action:ActionList){if(Action!=nullptr){Action->OnGameFeatureRegistering();Action->OnGameFeatureLoading();Action->OnGameFeatureActivating(Context);}}};ActivateListOfActions(CurrentExperience->Actions);for(constTObjectPtr<ULyraExperienceActionSet>&ActionSet:CurrentExperience->ActionSets){if(ActionSet!=nullptr){ActivateListOfActions(ActionSet->Actions);}}LoadState=ELyraExperienceLoadState::Loaded;OnExperienceLoaded_HighPriority.Broadcast(CurrentExperience);OnExperienceLoaded_HighPriority.Clear();OnExperienceLoaded.Broadcast(CurrentExperience);OnExperienceLoaded.Clear();OnExperienceLoaded_LowPriority.Broadcast(CurrentExperience);OnExperienceLoaded_LowPriority.Clear();#if!UE_SERVERULyraSettingsLocal::Get()->OnExperienceLoaded();#endif}

关键实现点:

  • 验证非已加载状态
  • 支持混沌测试延迟(用于模拟加载延迟)
  • 转换状态为ELyraExperienceLoadState::ExecutingActions
  • 创建游戏特性激活上下文,包含世界上下文信息
  • 激活动作列表的Lambda函数
  • 执行经验定义和动作集中的所有动作(注册→加载→激活)
  • 转换状态为ELyraExperienceLoadState::Loaded
  • 按优先级广播加载完成事件:
    • 高优先级(核心功能)
    • 普通优先级
    • 低优先级
  • 在客户端调用本地设置的经验加载完成回调

3. 网络同步机制

Lyra的Experience系统支持网络同步,确保客户端和服务器使用相同的经验配置:

voidULyraExperienceManagerComponent::OnRep_CurrentExperience(){StartExperienceLoad();}voidULyraExperienceManagerComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>&OutLifetimeProps)const{Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME(ThisClass,CurrentExperience);}

关键实现点:

  • 当前经验通过DOREPLIFETIME宏自动复制到客户端
  • 客户端在收到复制的经验后,自动调用StartExperienceLoad()开始加载
  • 加载流程在客户端和服务器上独立执行,但最终结果一致

4. 加载状态管理

Experience系统使用ELyraExperienceLoadState枚举管理加载状态:

enumclassELyraExperienceLoadState{Unloaded,// 未加载状态Loading,// 加载经验资源LoadingGameFeatures,// 加载游戏特性插件LoadingChaosTestingDelay,// 混沌测试延迟ExecutingActions,// 执行经验动作Loaded,// 完全加载完成Deactivating// 停用经验};

5. 加载流程的取消和清理

系统支持加载过程中的取消处理:

Handle->BindCancelDelegate(FStreamableDelegate::CreateLambda([OnAssetsLoadedDelegate](){OnAssetsLoadedDelegate.ExecuteIfBound();}));

在组件结束时,会尝试停用已激活的游戏特性插件:

voidULyraExperienceManagerComponent::EndPlay(constEEndPlayReason::Type EndPlayReason){Super::EndPlay(EndPlayReason);for(constFString&PluginURL:GameFeaturePluginURLs){if(ULyraExperienceManager::RequestToDeactivatePlugin(PluginURL)){UGameFeaturesSubsystem::Get().DeactivateGameFeaturePlugin(PluginURL);}}// 停用和清理动作// ...}

6. 加载状态查询

boolULyraExperienceManagerComponent::IsExperienceLoaded()const{return(LoadState==ELyraExperienceLoadState::Loaded)&&(CurrentExperience!=nullptr);}constULyraExperienceDefinition*ULyraExperienceManagerComponent::GetCurrentExperienceChecked()const{check(LoadState==ELyraExperienceLoadState::Loaded);check(CurrentExperience!=nullptr);returnCurrentExperience;}

7. 总结

Lyra的Experience系统加载流程具有以下特点:

  1. 异步加载模式:确保游戏在加载过程中保持响应性
  2. 状态驱动:通过明确的状态转换管理加载过程
  3. 模块化设计:将资源加载、插件激活和动作执行分离
  4. 网络同步:确保客户端和服务器使用相同的经验配置
  5. 优先级事件系统:支持不同优先级的加载完成回调
  6. 可测试性:包含混沌测试延迟功能
  7. 可扩展性:支持通过动作集扩展经验功能

这种设计确保了Experience系统的灵活性和可维护性,同时提供了良好的用户体验。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/16 2:59:57

Java Excel处理性能革命:FastExcel实现20倍加速的终极方案

Java Excel处理性能革命&#xff1a;FastExcel实现20倍加速的终极方案 【免费下载链接】fastexcel Generate and read big Excel files quickly 项目地址: https://gitcode.com/gh_mirrors/fas/fastexcel 在当今数据驱动的时代&#xff0c;Excel文件处理已成为Java开发中…

作者头像 李华
网站建设 2026/3/14 18:31:15

ELK+Filebeat实战

文章目录 前言一、什么是ELK二、ELK核心组件说明1、Elasticsearch1.1、什么是Elasticsearch1.2、Elasticsearch 作用1.3、Elasticsearch 应用场景1.4、Elasticsearch 工作原理 2、Logstash2.1、什么是Logstash2.2、Logstash作用2.3、Logstash应用场景2.4、Logstash工作原理 3、…

作者头像 李华
网站建设 2026/3/21 9:26:19

Lan Mouse终极指南:如何实现多设备鼠标键盘无缝共享?

Lan Mouse终极指南&#xff1a;如何实现多设备鼠标键盘无缝共享&#xff1f; 【免费下载链接】lan-mouse mouse & keyboard sharing via LAN 项目地址: https://gitcode.com/gh_mirrors/la/lan-mouse 在日常工作中&#xff0c;你是否经常需要在多台电脑之间来回切换…

作者头像 李华
网站建设 2026/3/23 14:14:47

如何快速掌握tiny-AES-c:轻量级AES加密的完整指南

如何快速掌握tiny-AES-c&#xff1a;轻量级AES加密的完整指南 【免费下载链接】tiny-AES-c Small portable AES128/192/256 in C 项目地址: https://gitcode.com/gh_mirrors/ti/tiny-AES-c tiny-AES-c是一款专为资源受限环境设计的超轻量级AES加密库&#xff0c;采用纯C…

作者头像 李华
网站建设 2026/3/22 4:47:58

阴阳师脚本使用指南:2025最新自动化工具快速上手教程

作为一款专为《阴阳师》玩家设计的自动化工具&#xff0c;OnmyojiAutoScript能够全面解放你的双手&#xff0c;轻松完成各类日常任务。这款阴阳师自动化工具采用先进的图像识别技术&#xff0c;通过智能决策系统实现游戏操作的全托管&#xff0c;让你告别重复枯燥的刷本时光。 …

作者头像 李华
网站建设 2026/3/23 1:54:56

KKManager完整使用指南:3步轻松管理游戏Mod

KKManager完整使用指南&#xff1a;3步轻松管理游戏Mod 【免费下载链接】KKManager Mod, plugin and card manager for games by Illusion that use BepInEx 项目地址: https://gitcode.com/gh_mirrors/kk/KKManager KKManager是一款专为Illusion游戏设计的Mod、插件和卡…

作者头像 李华