当前位置: 首页 > 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.cnnetsun.cn/news/54880.html

相关文章:

  • 31、集群架构全解析:类型、配置与最佳实践
  • AI Agent领域的痛点与创新解决方案
  • 44、网络安全之防火墙与病毒防护全解析
  • 50、未来信息技术趋势:关键技术解析与应用前景
  • 快速掌握yt-dlp-gui:Windows视频下载终极指南
  • Zotero-GPT插件API密钥配置终极指南:3步解决密钥错误问题
  • 哔哩哔哩Linux客户端深度体验与技术解析
  • 零基础构建虚拟文件系统:WinFsp实战指南
  • 解锁千万级3D资产宝库:Objaverse-XL实战应用全解析
  • 4小时变25分钟:飞书文档批量导出神器让备份效率飙升
  • 革命性突破:下一代Web图像处理技术深度解析
  • 网盘直链下载助手:轻松获取真实下载地址的终极解决方案
  • Day29:I2C 高级应用
  • Screenbox媒体播放器终极方案:Windows生态的完整播放指南
  • Res-Downloader资源嗅探器:告别资源下载烦恼的终极方案
  • 如何快速搭建个人音乐云:DSub Android客户端完整教程
  • 双螺旋3D圣诞树:JavaScript图形编程的技术深度解析
  • vue基于Spring Boot的篮球比赛CBA联赛管理系统应用和研究_x2ij33qg
  • vue基于Spring Boot的考公考编学习课程资料推荐系统_0hcxvdf4_
  • 基于 C++ 实现的智能物流配送系统模拟程序
  • ExifToolGUI终极指南:免费高效的图片元数据管理工具
  • RSSHub-Radar终极指南:快速掌握浏览器RSS订阅扩展的简单使用技巧
  • XMU-thesis:厦门大学学位论文LaTeX模板完全指南
  • 【原创改进代码】考虑Copula相关性和热泵灵活性的风电光伏出力波动平抑优化策略
  • LXMusic V250801音源系统深度探索:从架构设计到性能调优
  • TranslucentTB中文设置完整指南:让任务栏透明化工具说中文
  • 百度网盘下载加速终极指南:免费突破限速完整方案
  • 3步搞定Habitat-Matterport 3D数据集完整安装指南 [特殊字符]
  • 企业级RPA利器OpenRPA:零基础快速部署与实战应用完全指南
  • 如何免费解锁百度网盘SVIP极速下载:终极完整指南