Lyra的数据驱动之数据加载与引用

知乎同文:
Lyra的数据驱动之数据加载与引用 - 知乎 (zhihu.com)
Lyra是UE5发布的一个非常完整的案例项目,它包括了UE5的GameFeature,GamePlayAbility,EnhancedInput,EOS,ModularGamePlay,ModularGamePlayActors的整合使用,可以让我们更完整的学习几个大型插件的整合使用,大部分只需要配置文件就可以处理大量的代码和功能,提高独立游戏的开发效率,易于拓展的游戏架构,是不可多得的高质量学习项目。
个人比较菜第一次写这种项目分析文章,只是自己学习的一些拙见,也是记录,更好的了解这个项目的架构和各个部分的配置到底是怎样加载怎样引用的。文章尽量详细的说明流程,但是任然可能会有一些跳跃,需要自行查看其他代码。如有纰漏请指正,避免误人子弟。
Lyra的数据驱动围绕LyraExperienceDefinition(DataAsset)。
一. 入口


默认关卡中B_ExperienceList3D(Actor)主要作用是收集显示LyraUserFacingExperienceDefinition(主体LyraExperienceDefinition)配置以及生成关卡选择碰撞物体。


CommonSession_HostSessionRequest中Experience是ExperienceID.PrimaryAssetName其实就是LyraExperienceDefinition资源的Name

HostSession经过一系列的判断最后构造TravelURL,创建在线步骤基本相同。

ConstructTravelURL中将Experience从之前ExtraArgs参数中取出拼接TravelURL,最后调用Sessions->CreateSession进行创建session。
二. Experience的加载


在GameMode的InitGame中重写了一个下一帧执行的Timer,通过Timer中的函数从创建Level的参数中取到Experience的Name构造FPrimaryAssetId,再通过OnMatchAssignmentGiven函数去设置GameState下LyraExperienceManagerComponent的ExperienceId用于加载。

这个没有什么好说的就加载Experience指针赋值给LyraExperienceManagerComponent的CurrentExperience再调用StartExperienceLoad开始加载Experience配置里的文件。那客户端怎么办呢?我们可以看到CurrentExperience是一个使用ReplicatedUsing绑定了回调函数的变量,当CurrentExperience被设置后参生变化就会复制到客户端进行调用OnRep_CurrentExperience函数。OnRep_CurrentExperience中也就调用了StartExperienceLoad。

我们先来看看LyraExperienceDefinition里面有什么东西。
GameFeaturesToEnable 需要激活的GameFeature
DefaultPawnData 关于Pawn的PawnClass,Ability,Input
ActionSets Action的其他资源引用
Actions GameFeature中的Actions


打包资源set,将Experience自身和Experience->ActionSets都Add进BundleAssetList。标记资源是在服务器还是客户端加载。




之后收集所有的GameFeature的URLs进行加载激活,再调用OnExperienceFullLoadCompleted。

OnExperienceFullLoadCompleted中把Experience->ActionSet->Actions进行注册/加载/激活。至于GameFeature的组件Add流程和详情请参考大钊的GameFeature系列文章。截止到目前为止Experience的大部分资源已经被加载了。
三. Experience的引用
查找OnExperienceLoaded委托可以看见CallOrRegister_OnExperienceLoaded函数,再继续查找CallOrRegister_OnExperienceLoaded被谁调用。




查找结果中我们可以看到在Gamemode中和Playerstate中都进行的调用。先看LyraPlayerState::PostInitializeComponents中绑定了OnExperienceLoaded方法作为加载完成后的调用方法。OnExperienceLoaded方法是获取Experience中提到的PawnData。我们可以推测GetPawnDataForController中是通过获取Playerstate下的LyraExperienceManagerComponent组件里的Experience对象中的PawnData。

从GetPawnDataForController中看出也确实是这样,只不过加了一段直接去PlayerState中获取,因为有可能已经被赋值了。被赋值了直接返回,否则从LyraExperienceManagerComponent中获取。
现在回到LyraPlayerState::OnExperienceLoaded中SetPawnData。SetPawnData判断是否具有服务器权限,如果有就将PawnData->AbilitySets中的所有技能都一一GiveToAbilitySystem去。最后强制网络更新,将技能赋予也复制更新到客户端。




截止到目前位置Pawn的技能赋予就已经完成。
四. Experience其他引用
刚刚我们看完了Gamemode的InitGame(),接下来是GetDefaultPawnClassForController、SpawnDefaultPawnAtTransform两个比较重要的复写。



ALyraGameMode::GetDefaultPawnClassForController比较简单就是使用Experience下的PawnClass生成Pawn。ALyraGameMode::SpawnDefaultPawnAtTransform中查找Pawn下的LyraPawnExtensionComponent组件赋值PawnData。PawnData任然是复制变量,通过OnRep_PawnData进行客户端的执行CheckPawnReadyToInitialize(),服务器直接调用CheckPawnReadyToInitialize()。



LyraPawnExtensionComponent::CheckPawnReadyToInitialize通过一系列判断是否完成Pawn初始化最后通过OnPawnReadyToInitialize委托广播出去。

搜索OnPawnReadyToInitialize_RegisterAndCall我们可以看见在LyraHeroComponent::OnRegister中被绑定了ULyraHeroComponent::OnPawnReadyToInitialize函数。

在LyraHeroComponent::OnPawnReadyToInitialize下这里可以看见InitializeAbilitySystem和InitializePlayerInput,我们先看InitializeAbilitySystem,传入了位于PlayerState中的GamePlayAbility组件指针。



LyraPawnExtensionComponent::InitializeAbilitySystem中把传入进来的GamePlayAbility指针赋值给LyraPawnExtensionComponent的AbilitySystemComponent然后再设置Tag的关系映射,也就是之前在PawnData中的技能赋值下面配置的SetTagRelationshipMapping。可以看出SetTagRelationshipMapping提供了以后技能Tag之间的作用关系。



我们再回到LyraHeroComponent::OnPawnReadyToInitialize下的InitializePlayerInput。InitializePlayerInput首先将本地的输入设置进行了激活,然后将Extension->PawnData->InputConfig进行的BindAbilityActions技能Action绑定/BindNativeAction普通Action绑定。


到目前为止基本算是结束了,后面文章看时间可能会写关于GameFeature自定义AddComponent的文章。也就是Lyra项目中的UI也是通过配置来进行的。
项目还是看了很久,这篇文章也花了半天多。若有收获请点个赞或者留言支持下。