总览
Game Feature 项目最容易晚期炸的不是代码,而是资源:编辑器能看到,Cook 后找不到;客户端需要 UI,服务器却加载了贴图;活动包资源进了主包,DLC 失去意义;软引用没进 bundle,运行时同步加载卡顿。
GameFeatureData 本身是 Primary Asset
UGameFeatureData 继承 UPrimaryDataAsset。这很关键:Game Feature 能和 Asset Manager 的扫描、Bundle、Cook 体系对接。PrimaryAssetTypesToScan 让你声明插件目录里还有哪些 Primary Asset 类型需要扫描。
比如武器包里可以扫描:
| Primary Asset Type | 资产例子 |
|---|---|
WeaponDefinition | DA_RifleWeapon |
AbilitySet | DA_RifleAbilitySet |
ExperienceActionSet | DA_RifleExperienceActions |
ItemDefinition | DA_RifleItem |
Client/Server Bundle
UGameFeaturesSubsystemSettings 定义了两个常用 bundle state:
LoadStateClientLoadStateServer
引擎内置 AddComponents Action 在编辑器数据阶段会把组件类加入 Client/Server 对应 bundle。Lyra 的一些 Action 也会通过 meta=(AssetBundles="Client,Server") 或 AddAdditionalAssetBundleData 标注资源。
设计原则:
| 资源 | Bundle |
|---|---|
| UI Widget、图标、音效、相机表现 | Client |
| 服务器权威规则、Ability、AttributeSet、数据表 | Server 或 Client+Server |
| 双端都要预测/显示的 Ability | Client+Server |
| 纯编辑器工具 | 不进运行时 bundle |
Project Policy 可以控制预加载
UGameFeaturesProjectPolicies 有:
virtual TArray<FPrimaryAssetId> GetPreloadAssetListForGameFeature(
const UGameFeatureData* GameFeatureToLoad,
bool bIncludeLoadedAssets) const;
virtual const TArray<FName> GetPreloadBundleStateForPlugin(const FString& PluginName) const;
默认策略会按当前运行模式返回 Client/Server bundle。Dedicated Server 不应该加载 Client-only 数据,Client-only build 也不应该加载 Server-only 数据。
使用案例:活动商店 DLC
活动包资源分层:
- GameFeatureData:活动包入口。
- PrimaryAssetTypesToScan:活动商品、活动任务、活动奖励。
- Client Bundle:商品图标、商店 UI、展示 Mesh、音效。
- Server Bundle:价格表、库存规则、任务条件、奖励发放逻辑。
- Optional InstallBundle:高清展示资源或大型地图内容。
进入活动页前先 Load;玩家离开活动页且短时间不会回来,可以 Deactivate 或 Release optional data。
Cook 检查清单
- Game Feature 插件是否在正确目录并被项目识别为有效 GFP。
.uplugin依赖是否完整。PrimaryAssetTypesToScan是否覆盖插件内容目录。- 软引用资源是否通过 AssetBundleData 或 Primary Asset 进入 Cook。
- Dedicated Server 是否错误 Cook 客户端 UI 资源。
- DLC 包是否把活动资源和主包资源分离。
架构分析
Game Feature 资源管理要避免两种极端:一种是全硬引用,导致一个功能包激活就把所有东西拉进内存;另一种是全软引用但没进 Asset Manager,Cook 后丢资源或运行时同步加载。正确方式是:核心定义用 Primary Asset 管,表现资源挂 AssetBundle,Action 负责把它们声明到 Client/Server bundle,Project Policy 决定不同运行环境该加载哪些 bundle。
常见坑
- 编辑器能打开资源,但打包后
LoadSynchronous返回空。 - UI 图标写在 Server bundle,Dedicated Server Cook 变大。
- 玩法包依赖主工程里未公开的私有资产,DLC 单独 Cook 失败。
- 插件之间互相硬引用,无法独立卸载。
- 没做预加载,Active 阶段第一次打开 UI 卡一大下。
源码依据
UGameFeatureData 提供 PrimaryAssetTypesToScan。UGameFeaturesSubsystemSettings 提供 LoadStateClient 和 LoadStateServer。UDefaultGameFeaturesProjectPolicies::GetPreloadBundleStateForPlugin 按运行模式返回 Client/Server bundle。UGameFeatureAction_AddComponents::AddAdditionalAssetBundleData 会把组件类加入对应 bundle。
源码路径索引
GameFeatures/Public/GameFeatureData.hGameFeatures/Public/GameFeaturesSubsystemSettings.hGameFeatures/Public/GameFeaturesProjectPolicies.hGameFeatures/Private/GameFeatureData.cppGameFeatures/Private/GameFeatureAction_AddComponents.cppGameFeatures/Private/GameFeaturePluginStateMachine.cpp