UE5.8 Game Features 喂饭级专题

UE5.8 Game Features 专题(二):.uplugin、GameFeatureData 与目录结构

讲清 Game Feature 插件描述文件、BuiltInInitialFeatureState、ExplicitlyLoaded、GameFeatureData、Actions、PrimaryAssetTypesToScan、插件 Config 和推荐目录组织。

总览

Game Feature 插件有两个核心入口:.upluginUGameFeatureData.uplugin 是“系统怎么认识这个玩法包”,GameFeatureData 是“这个玩法包激活时做哪些动作”。这两个没设计好,后面 Action 写得再漂亮也会难维护。

UE5.8 Game Features 专题(二):.uplugin、GameFeatureData 与目录结构 配图
.uplugin 决定这个包如何被系统发现,GameFeatureData 决定这个包激活时做什么。

.uplugin 的关键字段

字段建议含义
CanContainContenttrue大多数玩法包要放资产
EnabledByDefaultfalse不让普通插件系统直接启用全部内容
ExplicitlyLoadedtrue由 Game Feature 流程显式加载
BuiltInInitialFeatureStateRegistered/Loaded/Active启动时自动推进到哪个状态
Plugins明确写依赖例如 GameFeatures、ModularGameplay、GAS、CommonUI

UE5.8 源码里 DetermineBuiltInInitialFeatureState 支持四个值:InstalledRegisteredLoadedActive。如果没有新字段,会回退到老的 BuiltInAutoRegister/BuiltInAutoLoad/BuiltInAutoActivate

四种初始状态怎么选

状态适合
Installed包存在,但启动时不注册,适合真正按需发现的内容
Registered启动时进入可加载状态,适合大多数内置玩法包
Loaded资源和代码准备好,但不激活,适合马上要用但要等玩法条件的包
Active开局就启用,适合基础模式或必备体验

初学建议用 Registered。它不会一启动就把所有 Action 执行掉,但 LoadGameFeaturePlugin PluginName 能直接测试。

GameFeatureData 里有什么

UGameFeatureData 继承 UPrimaryDataAsset,它有两个重点字段:

字段用途
Actions激活、停用时要执行的动作列表
PrimaryAssetTypesToScan告诉 Asset Manager 这个插件里有哪些 Primary Asset 类型要扫描

Action 是 instanced UObject,编辑器里可以直接在 GameFeatureData 的数组里加 Add Components、DataRegistry、WP Content、项目自定义 Action。

推荐目录结构

Plugins/GameFeatures/WeaponPack_Rifle/
  Config/
    Tags/WeaponPack_RifleTags.ini
  Content/
    DA_GameFeatureData_Rifle
    Weapons/DA_RifleWeapon
    Input/IMC_Rifle
    UI/WBP_RifleReticle
    Abilities/GA_RifleFire
  Source/
    WeaponPack_RifleRuntime/
      Public/
      Private/
  WeaponPack_Rifle.uplugin

命名上把插件名、资产名前缀、GameplayTag 前缀保持一致。比如 Feature.Weapon.RifleInput.Weapon.Rifle.FireUI.Weapon.Rifle.Reticle

插件 Config 怎么用

UGameFeatureDataInitializeBasePluginIniFileInitializeHierarchicalPluginIniFiles。这意味着 Game Feature 插件可以带配置文件,并在加载/激活阶段合入配置。适合放 GameplayTags、DataRegistry、平台差异、项目自定义设置。

不要把主工程必须存在的基础配置放在可选 Game Feature 插件里。否则插件未注册时,主工程启动就可能缺 Tag 或缺类。

使用案例:赛季活动包

一个赛季活动包可以这样拆:

  • .upluginBuiltInInitialFeatureState=Registered,上线后由服务器配置决定是否激活。
  • GameFeatureData Actions:Add Components 给 PlayerController 加活动任务追踪组件;Add DataRegistry Source 加活动奖励表;Add UI Widget 加活动入口。
  • PrimaryAssetTypesToScan:扫描活动任务、奖励、活动商店商品。
  • Config Tags:声明 Event.Season12.*

活动结束时停用插件,输入/UI/组件/数据源都应该跟着拆掉。

架构分析

.uplugin 是包级元数据,适合描述依赖、初始状态和加载策略;GameFeatureData 是玩法级数据,适合描述激活时要执行的动作;PrimaryAssetTypesToScan 是资源发现协议,适合把插件里的玩法定义交给 Asset Manager。三者不要互相替代:不要把运行时行为写进 .uplugin,也不要让 Action 临时扫描一堆未登记资源。

常见坑

  • EnabledByDefault=true 又希望运行时控制启停,语义冲突。
  • Active 玩法包里放大量非启动必要资源,首帧加载变慢。
  • 所有玩法包都依赖彼此,最后没有一个能独立测试。
  • Primary Asset 类型散在主工程和插件之间,Cook 时找不到资源。
  • 插件 Config 里声明了主工程启动必须依赖的 Tag,导致插件关闭后主工程不完整。

源码依据

UGameFeatureData 继承 UPrimaryDataAsset,有 ActionsPrimaryAssetTypesToScanUGameFeaturesSubsystem::DetermineBuiltInInitialFeatureState 在 UE5.8 中优先读取 BuiltInInitialFeatureState,支持 Installed、Registered、Loaded、Active,并保留老字段兼容。Lyra 的 ShooterCore 插件使用 ExplicitlyLoaded=trueBuiltInInitialFeatureState=Registered,是很好的项目参考。

源码路径索引

  • GameFeatures/Public/GameFeatureData.h
  • GameFeatures/Private/GameFeaturesSubsystem.cpp
  • GameFeatures/Private/GameFeatureData.cpp
  • GameFeatures/Public/GameFeaturesSubsystemSettings.h
  • Samples/Games/Lyra/Plugins/GameFeatures/ShooterCore/ShooterCore.uplugin