news 2026/8/19 14:10:12

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/8/19 10:05:41

TaskFlow任务编排框架:从零开始构建高效业务流程

TaskFlow任务编排框架&#xff1a;从零开始构建高效业务流程 【免费下载链接】taskflow taskflow是一款轻量、简单易用、可灵活扩展的通用任务编排框架&#xff0c;基于有向无环图(DAG)的方式实现&#xff0c;框架提供了组件复用、同步/异步编排、条件判断、分支选择等能力&…

作者头像 李华
网站建设 2026/8/19 7:31:51

百度网盘解析神器:告别龟速下载,轻松获取高速直链

百度网盘解析神器&#xff1a;告别龟速下载&#xff0c;轻松获取高速直链 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 还在为百度网盘的限速烦恼吗&#xff1f;每次下载大文…

作者头像 李华
网站建设 2026/8/19 13:43:52

在Remix和hardhat中集成UUPS升级合约

目录 1.在Remix中集成UUPS升级合约 2.在Hardhat中集成UUPS升级合约 上一篇讲了集成透明升级合约&#xff1a; https://blog.csdn.net/fyihdg/article/details/155883276 这一篇讲一下UUPS升级合约 1.在Remix中集成UUPS升级合约 首先准备好代码&#xff1a; // SPDX-Lice…

作者头像 李华
网站建设 2026/8/18 1:33:16

MuJoCo弹性插件实战指南:从基础建模到工业级软体机器人仿真

MuJoCo弹性插件实战指南&#xff1a;从基础建模到工业级软体机器人仿真 【免费下载链接】mujoco Multi-Joint dynamics with Contact. A general purpose physics simulator. 项目地址: https://gitcode.com/GitHub_Trending/mu/mujoco 在当今机器人技术快速发展的时代&…

作者头像 李华
网站建设 2026/8/19 0:07:44

Windows 11 LTSC应用商店恢复终极指南:快速安装Microsoft Store完整教程

Windows 11 LTSC版本作为企业级系统&#xff0c;默认不包含Microsoft Store应用商店&#xff0c;这给需要安装UWP应用的用户带来了不便。LTSC-Add-MicrosoftStore工具提供了一种简单有效的解决方案&#xff0c;让LTSC系统重新支持应用商店功能。本教程将详细介绍如何快速完成Wi…

作者头像 李华
网站建设 2026/8/19 2:17:45

FF14插件自动跳过动画:告别重复观看,专注核心战斗

FF14插件自动跳过动画&#xff1a;告别重复观看&#xff0c;专注核心战斗 【免费下载链接】FFXIV_ACT_CutsceneSkip 项目地址: https://gitcode.com/gh_mirrors/ff/FFXIV_ACT_CutsceneSkip 还在为每次刷副本都要手动跳过相同的过场动画而烦恼吗&#xff1f;《最终幻想X…

作者头像 李华