674 lines
16 KiB
Markdown
674 lines
16 KiB
Markdown
|
|
# Resource
|
|||
|
|
|
|||
|
|
## 模块概述
|
|||
|
|
|
|||
|
|
Resource 模块基于 YooAsset 封装了资源包初始化、版本管理、资源查询、同步/异步加载、实例化、缓存回收与低内存处理能力。
|
|||
|
|
|
|||
|
|
它是多个模块的底层依赖:
|
|||
|
|
|
|||
|
|
- `UI`:加载窗口和 Widget 预制体
|
|||
|
|
- `Audio`:加载音频资源
|
|||
|
|
- `Localization`:加载语言表
|
|||
|
|
- `GameObjectPool`:加载池对象原始 prefab
|
|||
|
|
- `Scene`:主场景与附加场景的资源加载链路
|
|||
|
|
|
|||
|
|
从当前实现来看,`ResourceService` 还额外提供了:
|
|||
|
|
|
|||
|
|
- 多包管理
|
|||
|
|
- 同一路径并发加载合并
|
|||
|
|
- 资源对象池缓存
|
|||
|
|
- 低内存时统一回收入口
|
|||
|
|
- 下载、版本、清单更新能力
|
|||
|
|
|
|||
|
|
## 快速开始
|
|||
|
|
|
|||
|
|
### 最少步骤
|
|||
|
|
|
|||
|
|
1. 在场景中挂载 `ResourceComponent`
|
|||
|
|
2. 配置 `PlayMode`、默认包名和解密服务名
|
|||
|
|
3. 游戏启动时调用 `InitPackageAsync`
|
|||
|
|
4. 通过 `GameApp.Resource` 或 `AppServices.Require<IResourceService>()` 加载资源
|
|||
|
|
|
|||
|
|
### 最小示例
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class ResourceQuickStart : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
await GameApp.Resource.InitPackageAsync();
|
|||
|
|
|
|||
|
|
Texture2D icon = await GameApp.Resource.LoadAssetAsync<Texture2D>("UI/Common/Icon");
|
|||
|
|
Debug.Log(icon != null);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 架构说明
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
ResourceComponent
|
|||
|
|
└─ ResourceService
|
|||
|
|
├─ YooAsset PackageMap
|
|||
|
|
├─ AssetInfo Cache
|
|||
|
|
├─ AssetObject Pool
|
|||
|
|
├─ Loading Operation Map
|
|||
|
|
├─ Download / Version / Manifest
|
|||
|
|
└─ ResourceExtComponent / AssetsReference
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 关键协作关系
|
|||
|
|
|
|||
|
|
- `ResourceComponent`:负责注册服务、配置运行模式并接管低内存回收节奏
|
|||
|
|
- `ResourceService`:负责包初始化、加载、缓存和释放
|
|||
|
|
- `AssetsReference`:负责把实例对象与源资源句柄关联起来,在对象销毁时自动释放源资源引用
|
|||
|
|
- `ResourceExtComponent`:负责追踪资源绑定目标并分帧回收无引用资源
|
|||
|
|
|
|||
|
|
### 运行模式
|
|||
|
|
|
|||
|
|
当前实现支持以下 `PlayMode`:
|
|||
|
|
|
|||
|
|
- `EditorSimulateMode`
|
|||
|
|
- `OfflinePlayMode`
|
|||
|
|
- `HostPlayMode`
|
|||
|
|
- `WebPlayMode`
|
|||
|
|
|
|||
|
|
不同模式决定初始化参数:
|
|||
|
|
|
|||
|
|
- **EditorSimulateMode**:编辑器模拟构建目录
|
|||
|
|
- **OfflinePlayMode**:本地内置资源
|
|||
|
|
- **HostPlayMode**:内置资源 + 缓存 + 远端下载
|
|||
|
|
- **WebPlayMode**:Web 环境资源拉取方式
|
|||
|
|
|
|||
|
|
### 并发加载合并机制
|
|||
|
|
|
|||
|
|
`ResourceService` 内部使用 `_assetLoadingOperations` 合并同一路径的并发加载请求。
|
|||
|
|
|
|||
|
|
这意味着:
|
|||
|
|
|
|||
|
|
- 多个系统同时加载同一个资源时,不会重复发起多次底层加载
|
|||
|
|
- 后来的请求会等待第一条加载链路完成,再复用结果
|
|||
|
|
|
|||
|
|
这对 UI 和公共图集资源特别有价值。
|
|||
|
|
|
|||
|
|
## 核心类与接口
|
|||
|
|
|
|||
|
|
### `IResourceService`
|
|||
|
|
|
|||
|
|
该接口同时覆盖:
|
|||
|
|
|
|||
|
|
- 包初始化
|
|||
|
|
- 包版本与清单管理
|
|||
|
|
- 资源存在性检查
|
|||
|
|
- 同步/异步加载
|
|||
|
|
- 场景对象实例化
|
|||
|
|
- 缓存清理
|
|||
|
|
- 低内存回收
|
|||
|
|
|
|||
|
|
### `ResourceComponent`
|
|||
|
|
|
|||
|
|
它是 Resource 模块在场景中的入口组件,主要职责:
|
|||
|
|
|
|||
|
|
- 注册 `ResourceService`
|
|||
|
|
- 配置默认包名 `PackageName`
|
|||
|
|
- 设置运行模式 `PlayMode`
|
|||
|
|
- 设置解密服务名 `decryptionServices`
|
|||
|
|
- 设置资源对象池参数
|
|||
|
|
- 接管 `Application.lowMemory` 事件
|
|||
|
|
|
|||
|
|
### `ResourceService`
|
|||
|
|
|
|||
|
|
从当前实现看,`ResourceService` 维护以下关键状态:
|
|||
|
|
|
|||
|
|
- `DefaultPackageName`
|
|||
|
|
- `PlayMode`
|
|||
|
|
- `PackageMap`
|
|||
|
|
- `_assetInfoMap`
|
|||
|
|
- `_assetLoadingOperations`
|
|||
|
|
- `_assetPool`
|
|||
|
|
|
|||
|
|
### `AssetsReference`
|
|||
|
|
|
|||
|
|
这是实例对象与源资源句柄的桥接组件。
|
|||
|
|
|
|||
|
|
作用:
|
|||
|
|
|
|||
|
|
- 当你通过 `LoadGameObject` / `LoadGameObjectAsync` 实例化资源时
|
|||
|
|
- 框架会在实例对象上自动挂一个 `AssetsReference`
|
|||
|
|
- 当该实例对象销毁时,对应源资源引用会自动 `UnloadAsset`
|
|||
|
|
|
|||
|
|
这就是为什么:
|
|||
|
|
|
|||
|
|
- `LoadGameObject` 返回的实例对象通常不需要你手动 `UnloadAsset`
|
|||
|
|
|
|||
|
|
### `ResourceExtComponent`
|
|||
|
|
|
|||
|
|
主要用于:
|
|||
|
|
|
|||
|
|
- 追踪已绑定给 UI、Sprite 或其他目标对象的资源
|
|||
|
|
- 自动清理已经失去引用的资源包装对象
|
|||
|
|
- 以分帧方式做回收,降低一次性遍历成本
|
|||
|
|
|
|||
|
|
## API 参考
|
|||
|
|
|
|||
|
|
以下内容按使用频率分组说明。
|
|||
|
|
|
|||
|
|
### 一、初始化与运行配置
|
|||
|
|
|
|||
|
|
#### `void Initialize()`
|
|||
|
|
|
|||
|
|
- 参数:无
|
|||
|
|
- 返回值:无
|
|||
|
|
- 说明:初始化 YooAsset、默认包与资产池
|
|||
|
|
- 备注:通常由 `ResourceComponent.Start()` 自动调用
|
|||
|
|
|
|||
|
|
#### `UniTask<bool> InitPackageAsync(string packageName = "", string hostServerURL = "", string fallbackHostServerURL = "")`
|
|||
|
|
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 可选参数:`hostServerURL`
|
|||
|
|
- 可选参数:`fallbackHostServerURL`
|
|||
|
|
- 返回值:`UniTask<bool>`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 初始化指定资源包
|
|||
|
|
- 如果 `packageName` 为空,则使用 `DefaultPackageName`
|
|||
|
|
- 在 Host/Web 模式下通常需要传入远端地址
|
|||
|
|
|
|||
|
|
异常与边界:
|
|||
|
|
|
|||
|
|
- 如果同一个包正在初始化或已成功初始化,会记录错误并直接返回失败结果
|
|||
|
|
- 初始化失败时任务会抛出异常
|
|||
|
|
|
|||
|
|
#### `string DefaultPackageName { get; set; }`
|
|||
|
|
|
|||
|
|
- 说明:默认资源包名
|
|||
|
|
- 推荐:整个项目统一默认包名约定
|
|||
|
|
|
|||
|
|
#### `EPlayMode PlayMode { get; set; }`
|
|||
|
|
|
|||
|
|
- 说明:资源系统运行模式
|
|||
|
|
- 注意:Editor 与真机配置往往不同
|
|||
|
|
|
|||
|
|
#### `string DecryptionServices { get; set; }`
|
|||
|
|
|
|||
|
|
- 说明:解密服务类型名
|
|||
|
|
- 注意:该值应是可被反射创建的类型全名
|
|||
|
|
|
|||
|
|
#### `bool AutoUnloadBundleWhenUnused { get; set; }`
|
|||
|
|
|
|||
|
|
- 说明:初始化参数中的自动卸载选项
|
|||
|
|
|
|||
|
|
### 二、版本与下载管理
|
|||
|
|
|
|||
|
|
#### `string GetPackageVersion(string customPackageName = "")`
|
|||
|
|
|
|||
|
|
- 可选参数:`customPackageName`
|
|||
|
|
- 返回值:包版本字符串
|
|||
|
|
|
|||
|
|
#### `RequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks = false, int timeout = 60, string customPackageName = "")`
|
|||
|
|
|
|||
|
|
- 可选参数:`appendTimeTicks`
|
|||
|
|
- 可选参数:`timeout`
|
|||
|
|
- 可选参数:`customPackageName`
|
|||
|
|
- 返回值:`RequestPackageVersionOperation`
|
|||
|
|
|
|||
|
|
#### `UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60, string customPackageName = "")`
|
|||
|
|
|
|||
|
|
- 必填参数:`packageVersion`
|
|||
|
|
- 可选参数:`timeout`
|
|||
|
|
- 可选参数:`customPackageName`
|
|||
|
|
- 返回值:`UpdatePackageManifestOperation`
|
|||
|
|
|
|||
|
|
#### `ResourceDownloaderOperation CreateResourceDownloader(string customPackageName = "")`
|
|||
|
|
|
|||
|
|
- 可选参数:`customPackageName`
|
|||
|
|
- 返回值:`ResourceDownloaderOperation`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 会使用当前 `DownloadingMaxNum` 和 `FailedTryAgain`
|
|||
|
|
|
|||
|
|
### 三、资源查询
|
|||
|
|
|
|||
|
|
#### `HasAssetResult HasAsset(string location, string packageName = "")`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`HasAssetResult`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 用于判断资源是否存在、是否在本地、是否需要远端下载
|
|||
|
|
|
|||
|
|
注意:
|
|||
|
|
|
|||
|
|
- 如果 `location` 为空会抛异常
|
|||
|
|
|
|||
|
|
#### `bool CheckLocationValid(string location, string packageName = "")`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`bool`
|
|||
|
|
|
|||
|
|
#### `AssetInfo GetAssetInfo(string location, string packageName = "")`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`AssetInfo`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 内部带有 `_assetInfoMap` 缓存
|
|||
|
|
- 同一路径重复获取成本较低
|
|||
|
|
|
|||
|
|
### 四、同步加载
|
|||
|
|
|
|||
|
|
#### `T LoadAsset<T>(string location, string packageName = "") where T : UnityEngine.Object`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`T`
|
|||
|
|
- 泛型约束:`T : UnityEngine.Object`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 同步加载资源
|
|||
|
|
- 首次加载会进入资源池缓存
|
|||
|
|
- 重复获取相同资源时会优先从 `_assetPool` 中复用
|
|||
|
|
|
|||
|
|
#### `GameObject LoadGameObject(string location, Transform parent = null, string packageName = "")`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`parent`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`GameObject`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 同步加载 prefab 并实例化
|
|||
|
|
- 实例对象会自动挂 `AssetsReference`
|
|||
|
|
- 销毁实例时会自动释放源资源引用
|
|||
|
|
|
|||
|
|
### 五、异步加载
|
|||
|
|
|
|||
|
|
#### `UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`cancellationToken`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`UniTask<T>`
|
|||
|
|
|
|||
|
|
#### `UniTask<GameObject> LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, string packageName = "")`
|
|||
|
|
|
|||
|
|
- 必填参数:`location`
|
|||
|
|
- 可选参数:`parent`
|
|||
|
|
- 可选参数:`cancellationToken`
|
|||
|
|
- 可选参数:`packageName`
|
|||
|
|
- 返回值:`UniTask<GameObject>`
|
|||
|
|
|
|||
|
|
### 六、回调式加载
|
|||
|
|
|
|||
|
|
#### `UniTask LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")`
|
|||
|
|
|
|||
|
|
#### `UniTask LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")`
|
|||
|
|
|
|||
|
|
`LoadAssetCallbacks` 中的回调签名:
|
|||
|
|
|
|||
|
|
- 成功:`(string assetName, object asset, float duration, object userData)`
|
|||
|
|
- 失败:`(string assetName, LoadResourceStatus status, string errorMessage, object userData)`
|
|||
|
|
- 进度:`(string assetName, float progress, object userData)`
|
|||
|
|
|
|||
|
|
适合:
|
|||
|
|
|
|||
|
|
- 旧式回调链
|
|||
|
|
- 想同时观察进度与错误
|
|||
|
|
- 不方便直接 `await` 的场景
|
|||
|
|
|
|||
|
|
### 七、句柄接口
|
|||
|
|
|
|||
|
|
#### `AssetHandle LoadAssetSyncHandle<T>(string location, string packageName = "") where T : UnityEngine.Object`
|
|||
|
|
|
|||
|
|
#### `AssetHandle LoadAssetAsyncHandle<T>(string location, string packageName = "") where T : UnityEngine.Object`
|
|||
|
|
|
|||
|
|
适合:
|
|||
|
|
|
|||
|
|
- 需要直接管理底层句柄
|
|||
|
|
- 需要和 YooAsset 句柄 API 配合
|
|||
|
|
|
|||
|
|
### 八、释放与回收
|
|||
|
|
|
|||
|
|
#### `void UnloadAsset(object asset)`
|
|||
|
|
|
|||
|
|
- 必填参数:`asset`
|
|||
|
|
- 返回值:无
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 本质上是把资源对象从 `_assetPool` 中 `Unspawn`
|
|||
|
|
|
|||
|
|
#### `void UnloadUnusedAssets()`
|
|||
|
|
|
|||
|
|
- 返回值:无
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 释放资源对象池中未使用的对象
|
|||
|
|
- 并对所有已成功初始化的包执行 `UnloadUnusedAssetsAsync`
|
|||
|
|
|
|||
|
|
#### `void ForceUnloadAllAssets()`
|
|||
|
|
|
|||
|
|
- 返回值:无
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 强制卸载所有资源
|
|||
|
|
- WebGL 下会直接警告并退出
|
|||
|
|
|
|||
|
|
#### `void ForceUnloadUnusedAssets(bool performGCCollect)`
|
|||
|
|
|
|||
|
|
- 必填参数:`performGCCollect`
|
|||
|
|
- 返回值:无
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 委托给 `ResourceComponent` 控制实际的系统资源回收时机
|
|||
|
|
|
|||
|
|
## 常见用法
|
|||
|
|
|
|||
|
|
### 1. 初始化默认包
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using AlicizaX.Resource.Runtime;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class ResourceInitExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
bool ok = await GameApp.Resource.InitPackageAsync();
|
|||
|
|
Debug.Log($"Init default package success: {ok}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 初始化远端包
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class HostModeInitExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
await GameApp.Resource.InitPackageAsync(
|
|||
|
|
packageName: "DefaultPackage",
|
|||
|
|
hostServerURL: "https://cdn.example.com/game",
|
|||
|
|
fallbackHostServerURL: "https://backup.example.com/game");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 同步加载配置资源
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class SyncLoadExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private void Start()
|
|||
|
|
{
|
|||
|
|
TextAsset config = GameApp.Resource.LoadAsset<TextAsset>("Config/GameBalance");
|
|||
|
|
Debug.Log(config != null ? config.text : "Config missing");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 异步加载图片资源
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class AsyncLoadExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
Sprite sprite = await GameApp.Resource.LoadAssetAsync<Sprite>("UI/Common/Atlas/Icon_Star");
|
|||
|
|
Debug.Log(sprite != null);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 加载并实例化 GameObject
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class InstantiateExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private GameObject _hero;
|
|||
|
|
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
_hero = await GameApp.Resource.LoadGameObjectAsync("Character/Hero.prefab", transform);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnDestroy()
|
|||
|
|
{
|
|||
|
|
if (_hero != null)
|
|||
|
|
{
|
|||
|
|
Destroy(_hero);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 这里不需要对 `_hero` 再调用 `UnloadAsset`
|
|||
|
|
- 销毁实例时 `AssetsReference` 会自动释放源资源引用
|
|||
|
|
|
|||
|
|
### 6. 使用回调式加载并监听进度
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using AlicizaX.Resource.Runtime;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class CallbackLoadExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
var callbacks = new LoadAssetCallbacks(
|
|||
|
|
(assetName, asset, duration, userData) =>
|
|||
|
|
{
|
|||
|
|
Debug.Log($"Load success: {assetName}, duration: {duration:F3}s");
|
|||
|
|
},
|
|||
|
|
(assetName, status, errorMessage, userData) =>
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Load failed: {assetName}, {status}, {errorMessage}");
|
|||
|
|
},
|
|||
|
|
(assetName, progress, userData) =>
|
|||
|
|
{
|
|||
|
|
Debug.Log($"Progress {assetName}: {progress:P0}");
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
await GameApp.Resource.LoadAssetAsync(
|
|||
|
|
"UI/Common/Icon",
|
|||
|
|
priority: 0,
|
|||
|
|
loadAssetCallbacks: callbacks,
|
|||
|
|
userData: null);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 7. 下载资源版本并更新清单
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class UpdateManifestExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
var versionOp = GameApp.Resource.RequestPackageVersionAsync();
|
|||
|
|
await versionOp.ToUniTask();
|
|||
|
|
|
|||
|
|
if (versionOp.Status == YooAsset.EOperationStatus.Succeed)
|
|||
|
|
{
|
|||
|
|
string version = versionOp.PackageVersion;
|
|||
|
|
var manifestOp = GameApp.Resource.UpdatePackageManifestAsync(version);
|
|||
|
|
await manifestOp.ToUniTask();
|
|||
|
|
Debug.Log($"Manifest updated to: {version}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 8. 创建下载器
|
|||
|
|
|
|||
|
|
```csharp
|
|||
|
|
using AlicizaX;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
public sealed class DownloaderExample : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
private async void Start()
|
|||
|
|
{
|
|||
|
|
var downloader = GameApp.Resource.CreateResourceDownloader();
|
|||
|
|
downloader.BeginDownload();
|
|||
|
|
await downloader.ToUniTask();
|
|||
|
|
Debug.Log($"Download status: {downloader.Status}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 运行行为细节
|
|||
|
|
|
|||
|
|
### 1. 重复加载同一路径会优先复用缓存
|
|||
|
|
|
|||
|
|
当前实现通过 `_assetPool` 保存 `AssetObject`,同一路径的资源会复用池内对象。
|
|||
|
|
|
|||
|
|
好处:
|
|||
|
|
|
|||
|
|
- 减少重复加载
|
|||
|
|
- 降低频繁生成/销毁底层句柄的开销
|
|||
|
|
|
|||
|
|
### 2. 并发同路径加载会合并请求
|
|||
|
|
|
|||
|
|
如果同一路径资源正在加载中:
|
|||
|
|
|
|||
|
|
- 后续请求不会重复发起底层加载
|
|||
|
|
- 会等待首个请求完成后再复用结果
|
|||
|
|
|
|||
|
|
### 3. `LoadGameObject` 与 `LoadAsset<T>` 的释放语义不同
|
|||
|
|
|
|||
|
|
#### `LoadAsset<T>`
|
|||
|
|
|
|||
|
|
- 返回的是资源对象本身
|
|||
|
|
- 如有需要可以显式 `UnloadAsset(asset)`
|
|||
|
|
|
|||
|
|
#### `LoadGameObject`
|
|||
|
|
|
|||
|
|
- 返回的是实例化后的场景对象
|
|||
|
|
- 源 prefab 资源句柄通过 `AssetsReference` 绑定到实例对象
|
|||
|
|
- 通常直接 `Destroy(instance)` 即可
|
|||
|
|
|
|||
|
|
### 4. 低内存行为
|
|||
|
|
|
|||
|
|
触发 `OnLowMemory()` 时:
|
|||
|
|
|
|||
|
|
- 会调用 `_forceUnloadUnusedAssetsAction`
|
|||
|
|
- 实际清理由 `ResourceComponent` 驱动
|
|||
|
|
|
|||
|
|
### 5. `AssetInfo` 有内部缓存
|
|||
|
|
|
|||
|
|
多次 `GetAssetInfo` 会命中 `_assetInfoMap`
|
|||
|
|
|
|||
|
|
适合:
|
|||
|
|
|
|||
|
|
- 频繁查询资源合法性
|
|||
|
|
- UI 打开前做路径校验
|
|||
|
|
|
|||
|
|
### 6. 失败行为
|
|||
|
|
|
|||
|
|
以下情况通常会导致异常或错误日志:
|
|||
|
|
|
|||
|
|
- 资源路径为空
|
|||
|
|
- 包不存在
|
|||
|
|
- 资源定位无效
|
|||
|
|
- 初始化失败
|
|||
|
|
|
|||
|
|
## 最佳实践
|
|||
|
|
|
|||
|
|
- 统一资源路径规范,避免大小写和目录命名混乱
|
|||
|
|
- 默认优先异步加载
|
|||
|
|
- 把“包初始化 / 版本更新 / 资源下载 / 资源使用”分成不同阶段处理
|
|||
|
|
- UI、音频、图集等高复用资源尽量走缓存复用
|
|||
|
|
- 对需要长期驻留的资源,业务层要明确生命周期,不要频繁反复加载
|
|||
|
|
|
|||
|
|
## 常见错误
|
|||
|
|
|
|||
|
|
### 1. 包未初始化就加载资源
|
|||
|
|
|
|||
|
|
现象:
|
|||
|
|
|
|||
|
|
- 资源查找失败
|
|||
|
|
- 返回空对象或直接异常
|
|||
|
|
|
|||
|
|
规避:
|
|||
|
|
|
|||
|
|
- 确保启动流程中先执行 `InitPackageAsync`
|
|||
|
|
|
|||
|
|
### 2. 默认包名与实际包名不一致
|
|||
|
|
|
|||
|
|
现象:
|
|||
|
|
|
|||
|
|
- 路径正确但查不到资源
|
|||
|
|
|
|||
|
|
规避:
|
|||
|
|
|
|||
|
|
- 统一 `DefaultPackageName`
|
|||
|
|
- 多包场景显式传入 `packageName`
|
|||
|
|
|
|||
|
|
### 3. 手动 `UnloadAsset` 已实例化场景对象
|
|||
|
|
|
|||
|
|
现象:
|
|||
|
|
|
|||
|
|
- 语义不清晰
|
|||
|
|
- 可能导致资源生命周期混乱
|
|||
|
|
|
|||
|
|
规避:
|
|||
|
|
|
|||
|
|
- `LoadGameObject` 返回的实例优先 `Destroy`
|
|||
|
|
|
|||
|
|
### 4. 解密服务类型名错误
|
|||
|
|
|
|||
|
|
现象:
|
|||
|
|
|
|||
|
|
- 初始化时反射失败
|
|||
|
|
|
|||
|
|
规避:
|
|||
|
|
|
|||
|
|
- `DecryptionServices` 必须是可反射创建的完整类型名
|
|||
|
|
|
|||
|
|
## 性能注意事项
|
|||
|
|
|
|||
|
|
- 避免在主线程大量同步加载
|
|||
|
|
- 常用资源优先缓存复用
|
|||
|
|
- 合理设置:
|
|||
|
|
- `AssetAutoReleaseInterval`
|
|||
|
|
- `AssetCapacity`
|
|||
|
|
- `AssetExpireTime`
|
|||
|
|
- `AssetPriority`
|
|||
|
|
- 高并发异步加载时,优先复用路径和包配置,发挥内部合并机制优势
|