当前位置: 首页 > news >正文

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系统的灵活性和可维护性,同时提供了良好的用户体验。

http://www.jsqmd.com/news/89876/

相关文章:

  • 抖音无水印视频下载工具完整使用指南:3分钟快速上手
  • ELK+Filebeat实战
  • 28、模块与向量空间:基础概念与维度理论
  • Android企业微信打卡助手使用指南:实现便捷打卡体验
  • openMES开源制造执行系统:5大核心优势助你打造智能工厂
  • AMD Ryzen性能调优终极指南:RyzenAdj工具的完整使用教程
  • OpenCore Legacy Patcher终极指南:让老款Mac重获新生的革命性工具
  • 【C++】继承与多态:从语法到底层原理
  • 系统与架构,进程,组织,组件,插件,构建之间的逻辑关系和工作机制
  • Springboot旅游网站o2j3b(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 3步搞定图像批量处理:Jimp实战指南与效率提升方案
  • 终极指南:HM3D大规模室内场景数据集的完整解决方案
  • MarkText主题定制终极指南:7天打造高效个性化写作环境的完整方案
  • 离线语音识别新标杆:Whisper.cpp全方位实践指南
  • RSSHub-Radar浏览器扩展:让信息订阅变得如此简单高效
  • Zepp Life刷步数完整解决方案:从入门到精通的技术实践
  • Lan Mouse终极指南:如何实现多设备鼠标键盘无缝共享?
  • Xcode调试救星:iOS设备支持文件快速部署全攻略
  • Springboot居民社区健康管理平台ue77n(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • iStore插件中心:OpenWRT插件管理的革命性解决方案
  • Shutter Encoder终极指南:专业视频编码工具快速上手
  • TaskFlow任务编排框架:从零开始构建高效业务流程
  • Android弹窗终极指南:BasePopup快速上手与实战技巧
  • HEIF Utility:Windows平台HEIF图像处理全攻略
  • day39 模型可视化与推理
  • 国家自然科学基金 申请项目评审意见反馈信
  • 暗黑3智能助手:解放双手的终极自动化解决方案
  • Zotero-GPT插件API密钥配置终极指南:3步解决密钥错误问题
  • 31、集群架构全解析:类型、配置与最佳实践
  • B站4K视频下载完整教程:2025最新工具快速上手指南