1
This commit is contained in:
parent
f4f0ea1754
commit
fcfa284f2c
@ -1,722 +0,0 @@
|
||||
# GameObjectPool 最优架构设计文档
|
||||
|
||||
## 1. 文档目标
|
||||
|
||||
本文档定义 `GameObjectPool` 模块的目标形态,用于支撑游戏内所有 `GameObject` 相关对象的统一池化,包括但不限于:
|
||||
|
||||
- 怪物 / NPC
|
||||
- 子弹 / 投射物
|
||||
- 特效 / 粒子 / VFXGraph
|
||||
- 掉落物 / 临时交互物
|
||||
- 飘字 / World UI
|
||||
- 音效壳对象
|
||||
- 可复用的场景装饰物
|
||||
|
||||
目标不是做一个“能复用 prefab 的基础对象池”,而是做一个“可覆盖全项目高频对象生命周期管理”的统一池化体系。
|
||||
|
||||
---
|
||||
|
||||
## 2. 现状结论
|
||||
|
||||
当前实现可以作为基础版对象池使用,但不是最优方案,主要原因如下:
|
||||
|
||||
- 只处理 `SetActive`、`SetParent`、Transform 复位,不具备统一的业务状态重置协议
|
||||
- 池满时只会返回 `null`,没有按对象类型区分溢出策略
|
||||
- 预热只支持静态固定值,不支持场景级、战斗级、波次级预热
|
||||
- 淘汰策略只基于时间,不包含优先级、预算、低内存策略
|
||||
- 清理调度依赖全量扫描,不适合大量池并存
|
||||
- 配置维度不足,无法精细支撑怪物、特效、子弹等不同对象类型
|
||||
- 缺少自动回收能力
|
||||
- 缺少运行时统计闭环,无法逼近最优容量配置
|
||||
|
||||
结论:
|
||||
|
||||
- 当前实现可以继续作为底层雏形
|
||||
- 不建议直接扩写成最终方案
|
||||
- 最优方向应升级为“分层池化架构”
|
||||
|
||||
---
|
||||
|
||||
## 3. 设计目标
|
||||
|
||||
### 3.1 功能目标
|
||||
|
||||
- 统一管理所有 `GameObject` 池化对象
|
||||
- 支持同步获取、异步获取、预热、回收、自动回收
|
||||
- 支持对象在复用前后执行自定义重置
|
||||
- 支持按对象类型定义不同的容量与淘汰策略
|
||||
- 支持运行时统计与调优建议导出
|
||||
- 支持低内存场景下的激进回收
|
||||
|
||||
### 3.2 性能目标
|
||||
|
||||
- 高频借还路径保持 O(1) 或近似 O(1)
|
||||
- 避免重复加载同一 prefab
|
||||
- 避免单帧大量 Instantiate / Destroy
|
||||
- 清理与预热都采用预算驱动,而不是无上限循环
|
||||
- 复杂对象允许使用轻量休眠,而非强制全量 `SetActive`
|
||||
|
||||
### 3.3 工程目标
|
||||
|
||||
- 配置清晰,可由策划 / TA / 程序共同维护
|
||||
- 业务接入方式统一,不让每个系统各自发明对象池
|
||||
- 支持逐步迁移,兼容现有 `GameObjectPoolManager`
|
||||
|
||||
---
|
||||
|
||||
## 4. 总体架构
|
||||
|
||||
推荐采用三层结构。
|
||||
|
||||
### 4.1 第一层:Prefab 池层
|
||||
|
||||
职责:
|
||||
|
||||
- prefab 资源加载与引用持有
|
||||
- 单 prefab 实例池管理
|
||||
- 容量控制
|
||||
- 预热
|
||||
- 淘汰
|
||||
- 调度
|
||||
|
||||
建议保留当前 `RuntimePrefabPool` 的职责方向,但增强其策略能力。
|
||||
|
||||
### 4.2 第二层:实例生命周期层
|
||||
|
||||
职责:
|
||||
|
||||
- 统一对象创建后初始化
|
||||
- 对象借出前重置
|
||||
- 对象归还前清理
|
||||
- 对象销毁前释放内部资源
|
||||
- 管理自动回收与上下文注入
|
||||
|
||||
该层是当前模块最缺失的部分,也是怪物、子弹、特效能够统一纳入池化的关键。
|
||||
|
||||
### 4.3 第三层:业务门面层
|
||||
|
||||
职责:
|
||||
|
||||
- 向业务提供强类型 API
|
||||
- 隐藏字符串路径、组名、预热细节
|
||||
- 承载特定对象的默认策略
|
||||
|
||||
示例:
|
||||
|
||||
```csharp
|
||||
Enemy enemy = enemyPool.Spawn(enemyId, spawnContext);
|
||||
Bullet bullet = bulletPool.Spawn(bulletConfigId, spawnContext);
|
||||
FxHandle fx = fxPool.Play(fxId, position, rotation, autoRecycle: true);
|
||||
```
|
||||
|
||||
不建议把字符串 `assetPath` 作为业务层唯一入口。
|
||||
字符串路径池应作为底层资源定位方式,而不是最终业务接口。
|
||||
|
||||
---
|
||||
|
||||
## 5. 生命周期协议设计
|
||||
|
||||
统一池化必须提供明确的生命周期协议。
|
||||
|
||||
### 5.1 核心接口
|
||||
|
||||
```csharp
|
||||
public interface IGameObjectPoolable
|
||||
{
|
||||
void OnPoolCreate();
|
||||
void OnPoolGet(in PoolSpawnContext context);
|
||||
void OnPoolRelease();
|
||||
void OnPoolDestroy();
|
||||
}
|
||||
```
|
||||
|
||||
语义建议:
|
||||
|
||||
- `OnPoolCreate`
|
||||
仅在实例第一次创建后调用一次
|
||||
- `OnPoolGet`
|
||||
每次借出时调用,用于注入上下文、重置运行态
|
||||
- `OnPoolRelease`
|
||||
每次归还时调用,用于停止逻辑、清理状态
|
||||
- `OnPoolDestroy`
|
||||
实例真正销毁前调用,用于释放自持资源
|
||||
|
||||
### 5.2 可选扩展接口
|
||||
|
||||
```csharp
|
||||
public interface IPoolAutoRecycle
|
||||
{
|
||||
bool TryGetAutoRecycleDelay(out float delaySeconds);
|
||||
}
|
||||
|
||||
public interface IPoolResettablePhysics
|
||||
{
|
||||
void ResetPhysicsState();
|
||||
}
|
||||
|
||||
public interface IPoolResettableVisual
|
||||
{
|
||||
void ResetVisualState();
|
||||
}
|
||||
|
||||
public interface IPoolResettableAnimation
|
||||
{
|
||||
void ResetAnimationState();
|
||||
}
|
||||
|
||||
public interface IPoolSleepable
|
||||
{
|
||||
void EnterSleep();
|
||||
void ExitSleep(in PoolSpawnContext context);
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `IPoolSleepable` 主要给怪物 / NPC 这类重对象使用
|
||||
- `IPoolResettablePhysics` 适合子弹、投射物、掉落物
|
||||
- `IPoolResettableVisual` 适合特效、Trail、VFXGraph、Renderer 状态清理
|
||||
|
||||
### 5.3 PoolSpawnContext
|
||||
|
||||
`OnPoolGet` 需要统一上下文,避免靠外部脚本到处手动赋值。
|
||||
|
||||
建议结构:
|
||||
|
||||
```csharp
|
||||
public readonly struct PoolSpawnContext
|
||||
{
|
||||
public readonly string AssetPath;
|
||||
public readonly string Group;
|
||||
public readonly Transform Parent;
|
||||
public readonly Vector3 Position;
|
||||
public readonly Quaternion Rotation;
|
||||
public readonly object UserData;
|
||||
public readonly int OwnerId;
|
||||
public readonly int TeamId;
|
||||
public readonly uint SpawnFrame;
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `UserData` 用于挂通用扩展参数
|
||||
- 高频场景可以进一步拆成强类型上下文
|
||||
|
||||
---
|
||||
|
||||
## 6. 池实例状态机
|
||||
|
||||
每个实例建议具备明确状态:
|
||||
|
||||
- `Uninitialized`
|
||||
- `Inactive`
|
||||
- `Active`
|
||||
- `Releasing`
|
||||
- `Destroying`
|
||||
|
||||
状态转换:
|
||||
|
||||
```text
|
||||
Create -> Inactive -> Active -> Releasing -> Inactive
|
||||
Create -> Inactive -> Destroying -> Destroy
|
||||
Active -> Destroying -> Destroy
|
||||
```
|
||||
|
||||
价值:
|
||||
|
||||
- 避免重复回收
|
||||
- 避免回收中再次借出
|
||||
- 便于统计与调试
|
||||
- 便于做自动回收与异步保护
|
||||
|
||||
---
|
||||
|
||||
## 7. 配置模型设计
|
||||
|
||||
当前 `PoolConfig` 维度不够,建议升级为两层配置:
|
||||
|
||||
- `PoolProfile`
|
||||
- `PoolRule`
|
||||
|
||||
### 7.1 PoolProfile
|
||||
|
||||
定义一类对象的默认策略,例如:
|
||||
|
||||
- `BulletProfile`
|
||||
- `FxProfile`
|
||||
- `EnemyProfile`
|
||||
- `UiWorldProfile`
|
||||
|
||||
示例字段:
|
||||
|
||||
```csharp
|
||||
public sealed class PoolProfile
|
||||
{
|
||||
public string profileName;
|
||||
public PoolObjectKind objectKind;
|
||||
public PoolOverflowPolicy overflowPolicy;
|
||||
public PoolTrimPolicy trimPolicy;
|
||||
public PoolActivationMode activationMode;
|
||||
public PoolResetMode resetMode;
|
||||
|
||||
public int minRetained;
|
||||
public int softCapacity;
|
||||
public int hardCapacity;
|
||||
|
||||
public float idleTrimDelay;
|
||||
public float prefabUnloadDelay;
|
||||
public float autoRecycleDelay;
|
||||
|
||||
public int trimBatchPerTick;
|
||||
public int warmupBatchPerFrame;
|
||||
public float warmupFrameBudgetMs;
|
||||
|
||||
public bool allowRuntimeExpand;
|
||||
public bool preloadOnInitialize;
|
||||
public bool keepPrefabResident;
|
||||
public bool aggressiveTrimOnLowMemory;
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 PoolRule
|
||||
|
||||
定义具体资源命中规则。
|
||||
|
||||
```csharp
|
||||
public sealed class PoolRule
|
||||
{
|
||||
public string group;
|
||||
public string assetPath;
|
||||
public PoolMatchMode matchMode;
|
||||
public PoolResourceLoaderType loaderType;
|
||||
public string profileName;
|
||||
|
||||
public bool overrideCapacity;
|
||||
public int minRetained;
|
||||
public int softCapacity;
|
||||
public int hardCapacity;
|
||||
|
||||
public bool overridePrewarm;
|
||||
public int prewarmCount;
|
||||
public PoolPrewarmPhase prewarmPhase;
|
||||
|
||||
public int priority;
|
||||
}
|
||||
```
|
||||
|
||||
设计原则:
|
||||
|
||||
- `Profile` 管类型策略
|
||||
- `Rule` 管具体命中
|
||||
- 高频热点对象优先使用 `Exact`
|
||||
- `Prefix` 只做默认兜底
|
||||
|
||||
---
|
||||
|
||||
## 8. 核心枚举草案
|
||||
|
||||
### 8.1 对象类型
|
||||
|
||||
```csharp
|
||||
public enum PoolObjectKind
|
||||
{
|
||||
Default = 0,
|
||||
Bullet = 1,
|
||||
Effect = 2,
|
||||
Enemy = 3,
|
||||
Npc = 4,
|
||||
Pickup = 5,
|
||||
WorldUi = 6,
|
||||
AudioProxy = 7,
|
||||
SceneProp = 8
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 池满策略
|
||||
|
||||
```csharp
|
||||
public enum PoolOverflowPolicy
|
||||
{
|
||||
FailFast = 0,
|
||||
InstantiateOneShot = 1,
|
||||
AutoExpand = 2,
|
||||
RecycleOldestInactive = 3,
|
||||
DropNewestRequest = 4
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 清理策略
|
||||
|
||||
```csharp
|
||||
public enum PoolTrimPolicy
|
||||
{
|
||||
None = 0,
|
||||
IdleOnly = 1,
|
||||
IdleAndPriority = 2,
|
||||
AggressiveOnLowMemory = 3
|
||||
}
|
||||
```
|
||||
|
||||
### 8.4 激活模式
|
||||
|
||||
```csharp
|
||||
public enum PoolActivationMode
|
||||
{
|
||||
SetActive = 0,
|
||||
SleepWake = 1,
|
||||
Custom = 2
|
||||
}
|
||||
```
|
||||
|
||||
### 8.5 重置模式
|
||||
|
||||
```csharp
|
||||
public enum PoolResetMode
|
||||
{
|
||||
TransformOnly = 0,
|
||||
PoolableCallbacks = 1,
|
||||
FullReset = 2,
|
||||
Custom = 3
|
||||
}
|
||||
```
|
||||
|
||||
### 8.6 预热阶段
|
||||
|
||||
```csharp
|
||||
public enum PoolPrewarmPhase
|
||||
{
|
||||
None = 0,
|
||||
AppInitialize = 1,
|
||||
SceneLoad = 2,
|
||||
BattlePrepare = 3,
|
||||
WavePrepare = 4,
|
||||
OnDemand = 5
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 不同对象类型的推荐策略
|
||||
|
||||
### 9.1 子弹
|
||||
|
||||
建议:
|
||||
|
||||
- `softCapacity` 较高
|
||||
- `hardCapacity` 可比 `softCapacity` 高 1.5 到 2 倍
|
||||
- 默认支持 `AutoExpand` 或 `InstantiateOneShot`
|
||||
- 必须支持自动回收
|
||||
- 必须清理 `Rigidbody / Collider / TrailRenderer`
|
||||
- prefab 通常常驻,不建议频繁 unload
|
||||
|
||||
### 9.2 特效 / 粒子
|
||||
|
||||
建议:
|
||||
|
||||
- 区分关键特效与普通特效
|
||||
- 普通特效允许 `DropNewestRequest`
|
||||
- 回收时必须清理所有粒子系统、Trail、音效播放状态
|
||||
- 支持“播完自动回池”
|
||||
- 预热由场景和技能装配共同驱动
|
||||
|
||||
### 9.3 怪物 / NPC
|
||||
|
||||
建议:
|
||||
|
||||
- 不建议只依赖通用 `SetActive`
|
||||
- 必须实现 `IGameObjectPoolable`
|
||||
- 推荐支持 `SleepWake`
|
||||
- 必须有 `minRetained`
|
||||
- 池满时不建议直接 `null`
|
||||
- 场景切换 / 波次结束后再做结构性收缩
|
||||
|
||||
### 9.4 掉落物 / 临时交互物
|
||||
|
||||
建议:
|
||||
|
||||
- 适合通用池
|
||||
- 支持超时自动回收
|
||||
- 支持来源信息重置
|
||||
|
||||
### 9.5 飘字 / World UI
|
||||
|
||||
建议:
|
||||
|
||||
- 高度适合池化
|
||||
- 必须自动回收
|
||||
- 必须重置 tween / alpha / scale / text / follow target
|
||||
|
||||
---
|
||||
|
||||
## 10. 预热策略设计
|
||||
|
||||
### 10.1 预热阶段
|
||||
|
||||
预热必须是分阶段的,而不是只靠初始化时一次性完成。
|
||||
|
||||
建议阶段:
|
||||
|
||||
- `AppInitialize`
|
||||
- `SceneLoad`
|
||||
- `BattlePrepare`
|
||||
- `WavePrepare`
|
||||
- `OnDemand`
|
||||
|
||||
### 10.2 预热预算
|
||||
|
||||
预热不允许无限制同步创建。
|
||||
|
||||
建议加入:
|
||||
|
||||
- 每帧最大创建数 `warmupBatchPerFrame`
|
||||
- 每帧时间预算 `warmupFrameBudgetMs`
|
||||
- 大对象延迟到非关键帧创建
|
||||
|
||||
### 10.3 自适应预热
|
||||
|
||||
建议收集以下统计并用于反哺配置:
|
||||
|
||||
- `peakActive`
|
||||
- `peakTotal`
|
||||
- `missCount`
|
||||
- `expandCount`
|
||||
- `poolExhaustedCount`
|
||||
|
||||
由此生成:
|
||||
|
||||
- 推荐 `softCapacity`
|
||||
- 推荐 `prewarmCount`
|
||||
- 推荐 `minRetained`
|
||||
|
||||
---
|
||||
|
||||
## 11. 淘汰策略设计
|
||||
|
||||
### 11.1 默认原则
|
||||
|
||||
淘汰不能只看时间,还应结合:
|
||||
|
||||
- 空闲时间
|
||||
- 对象优先级
|
||||
- 当前是否战斗中
|
||||
- 当前内存压力
|
||||
- 当前池容量是否超过软上限
|
||||
|
||||
### 11.2 推荐容量模型
|
||||
|
||||
- `minRetained`
|
||||
最低保有量,正常回收不低于该值
|
||||
- `softCapacity`
|
||||
常态推荐容量
|
||||
- `hardCapacity`
|
||||
绝对上限
|
||||
|
||||
### 11.3 销毁预算
|
||||
|
||||
回收策略必须预算化:
|
||||
|
||||
- 每 tick 最多回收 `trimBatchPerTick`
|
||||
- 必要时可以带时间预算,例如每帧不超过 `X ms`
|
||||
|
||||
这样可避免同一帧大量 `Destroy`
|
||||
|
||||
### 11.4 低内存策略
|
||||
|
||||
当收到 `Application.lowMemory` 时:
|
||||
|
||||
- 忽略部分 `minRetained`
|
||||
- 优先回收低优先级池
|
||||
- 优先卸载不常用 prefab
|
||||
- 进入短时激进回收模式
|
||||
|
||||
---
|
||||
|
||||
## 12. 调度策略设计
|
||||
|
||||
当前全量扫描策略不适合作为最终版。
|
||||
|
||||
推荐:
|
||||
|
||||
- 用最小堆维护池的下次清理时间
|
||||
- 池状态变化时只更新自己的 `nextDueTime`
|
||||
- 调度器只处理到期池
|
||||
- 清理和预热都按 budget 驱动
|
||||
|
||||
这样可以避免:
|
||||
|
||||
- 每次回收都扫描所有池
|
||||
- 大量池同时存在时的调度浪费
|
||||
|
||||
---
|
||||
|
||||
## 13. 自动回收设计
|
||||
|
||||
推荐提供一组通用 helper / component:
|
||||
|
||||
- `ReturnToPoolAfterSeconds`
|
||||
- `ReturnToPoolOnParticleStopped`
|
||||
- `ReturnToPoolOnAnimatorStateExit`
|
||||
- `ReturnToPoolOnAudioFinished`
|
||||
- `ReturnToPoolOnDistanceExceeded`
|
||||
- `ReturnToPoolOnCollision`
|
||||
|
||||
目标:
|
||||
|
||||
- 业务不重复造轮子
|
||||
- 自动回收行为可视化配置
|
||||
- 减少“忘记 Release”导致的泄漏
|
||||
|
||||
---
|
||||
|
||||
## 14. 运行时统计设计
|
||||
|
||||
最优方案必须带统计闭环。
|
||||
|
||||
每个池建议统计:
|
||||
|
||||
- `acquireCount`
|
||||
- `releaseCount`
|
||||
- `hitCount`
|
||||
- `missCount`
|
||||
- `peakActive`
|
||||
- `peakTotal`
|
||||
- `expandCount`
|
||||
- `exhaustedCount`
|
||||
- `autoRecycleCount`
|
||||
- `destroyCount`
|
||||
- `avgLifetime`
|
||||
- `avgIdleTime`
|
||||
- `avgAcquireCostMs`
|
||||
- `avgReleaseCostMs`
|
||||
|
||||
调试用途:
|
||||
|
||||
- Inspector 面板
|
||||
- 运行时快照
|
||||
- CSV / JSON 导出
|
||||
- 自动生成调优建议
|
||||
|
||||
---
|
||||
|
||||
## 15. 推荐默认配置区间
|
||||
|
||||
以下是默认建议值,不是硬编码结论,应由运行时统计修正。
|
||||
|
||||
### 15.1 通用默认
|
||||
|
||||
- `minRetained = 2 ~ 8`
|
||||
- `softCapacity = 8 ~ 32`
|
||||
- `hardCapacity = softCapacity * 1.5 ~ 2`
|
||||
- `idleTrimDelay = 15s ~ 60s`
|
||||
- `prefabUnloadDelay = 60s ~ 300s`
|
||||
- `trimBatchPerTick = 1 ~ 4`
|
||||
|
||||
### 15.2 子弹默认
|
||||
|
||||
- `minRetained = 16`
|
||||
- `softCapacity = 64`
|
||||
- `hardCapacity = 128`
|
||||
- `overflowPolicy = AutoExpand`
|
||||
- `prefabUnloadDelay = 300s`
|
||||
|
||||
### 15.3 普通特效默认
|
||||
|
||||
- `minRetained = 4`
|
||||
- `softCapacity = 16`
|
||||
- `hardCapacity = 32`
|
||||
- `overflowPolicy = DropNewestRequest`
|
||||
- `idleTrimDelay = 20s`
|
||||
|
||||
### 15.4 怪物默认
|
||||
|
||||
- `minRetained = 2`
|
||||
- `softCapacity = 8`
|
||||
- `hardCapacity = 16`
|
||||
- `overflowPolicy = AutoExpand`
|
||||
- `activationMode = SleepWake`
|
||||
|
||||
---
|
||||
|
||||
## 16. 与当前实现的映射关系
|
||||
|
||||
当前模块中可保留的部分:
|
||||
|
||||
- `GameObjectPoolManager`
|
||||
继续作为总入口和调度器雏形
|
||||
- `RuntimePrefabPool`
|
||||
继续作为单 prefab 池雏形
|
||||
- `PoolConfig`
|
||||
升级为新配置模型的一部分
|
||||
- `IResourceLoader`
|
||||
可继续作为资源加载抽象
|
||||
|
||||
需要重点重构的部分:
|
||||
|
||||
- 实例生命周期协议
|
||||
- 池满策略
|
||||
- 预热与清理预算调度
|
||||
- 统计系统
|
||||
- 自动回收组件
|
||||
- 怪物/特效/子弹的分类默认策略
|
||||
|
||||
---
|
||||
|
||||
## 17. 迁移路线
|
||||
|
||||
建议分四个阶段落地。
|
||||
|
||||
### 阶段 1:补生命周期协议
|
||||
|
||||
目标:
|
||||
|
||||
- 引入 `IGameObjectPoolable`
|
||||
- Acquire / Release 时统一回调
|
||||
- 允许对象自定义重置
|
||||
|
||||
### 阶段 2:补配置模型
|
||||
|
||||
目标:
|
||||
|
||||
- 引入 `PoolProfile + PoolRule`
|
||||
- 加入 `minRetained / softCapacity / hardCapacity / overflowPolicy`
|
||||
- 兼容旧 `PoolConfig`
|
||||
|
||||
### 阶段 3:补自动回收与预算调度
|
||||
|
||||
目标:
|
||||
|
||||
- 自动回收 helper
|
||||
- 分帧 warmup
|
||||
- 预算式 trim
|
||||
- 低内存模式
|
||||
|
||||
### 阶段 4:补统计与业务门面
|
||||
|
||||
目标:
|
||||
|
||||
- 运行时统计面板
|
||||
- 容量推荐导出
|
||||
- `EnemyPool / BulletPool / FxPool` 业务门面
|
||||
|
||||
---
|
||||
|
||||
## 18. 最终结论
|
||||
|
||||
最优对象池方案不是单一 `GameObject` 缓存容器,而是:
|
||||
|
||||
- 以 prefab 池为底层
|
||||
- 以生命周期协议为核心
|
||||
- 以分类策略为手段
|
||||
- 以预算调度为性能保障
|
||||
- 以统计闭环为调优依据
|
||||
|
||||
如果后续按本文档实施,建议优先级如下:
|
||||
|
||||
1. `IGameObjectPoolable` 与 `PoolSpawnContext`
|
||||
2. `PoolProfile + PoolRule`
|
||||
3. `PoolOverflowPolicy`
|
||||
4. 自动回收 helper
|
||||
5. 分帧预热与预算清理
|
||||
6. 运行时统计与调优导出
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c2737cf20d46c7814c0552b7f0720d
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loading…
Reference in New Issue
Block a user