三国卡牌客户端基础资源仓库
yyl
2026-02-11 06f2998ed8fcd05c9e1acbf16dd99ce9c8fb3adc
h5 资源系统改造
4个文件已修改
25个文件已添加
1429 ■■■■■ 已修改文件
Assets/AssetBundleCollectorSetting.asset 143 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/YooAsset.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/YooAsset/AddressByRelativePath.cs 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/YooAsset/AddressByRelativePath.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Common/IYooAssetBridge.cs 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Common/IYooAssetBridge.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Launch.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/LocalResManager.cs 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/YooAssetInitializer.cs 403 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/YooAssetInitializer.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/UI/LaunchWins/LaunchExWin.cs 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.MiniGame.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.MiniGame/README.md 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.MiniGame/README.md.meta 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/AsyncOperationBaseExtensions.cs 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/AsyncOperationBaseExtensions.cs.meta 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/OperationHandleBaseExtensions.cs 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/OperationHandleBaseExtensions.cs.meta 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/UniTask.YooAsset.asmdef 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/UniTask.YooAsset.asmdef.meta 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/UniTaskRef.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/UniTaskRef/UniTaskRef.asmref 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/UniTaskRef/UniTaskRef.asmref.meta 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/UniTaskRef/_InternalVisibleTo.cs 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Plugins/YooAsset.UniTask/UniTaskRef/_InternalVisibleTo.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/AssetBundleCollectorSetting.asset
@@ -38,6 +38,43 @@
        FilterRuleName: CollectAll
        AssetTags: 
        UserData: 
      - CollectPath: Assets/ResourcesOut/UIComp
        CollectorGUID: cafb96babf67f0e47aa47d7bd7e851f9
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Sprite
        CollectorGUID: d525c1ea56911ef46968923700fee47f
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Texture
        CollectorGUID: cc4265f3ee528e64e8afa76bd8f7d3f7
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
    - GroupName: Font
      GroupDesc:
      AssetTags:
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/Font
        CollectorGUID: 6c72fee81b7c8804dbc80d80a5770197
        CollectorType: 0
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
  - PackageName: Prefab
    PackageDesc: all prefab
    EnableAddressable: 1
@@ -52,8 +89,48 @@
      AssetTags: 
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/Prefab
        CollectorGUID: 84f0993784b8e8d41a68d0e1e2be57bd
      - CollectPath: Assets/ResourcesOut/BuiltIn
        CollectorGUID: e5f9df9a324df2b46b1a92fa8da26b67
        CollectorType: 0
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Shader
        CollectorGUID: 01ad80e2bb073fb46ad906e3572fbe50
        CollectorType: 0
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Materials
        CollectorGUID: 676c8b4532d6ca646804bf73ed43dd96
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/ScriptableObject
        CollectorGUID: 1482db32e9d88d444bc22e54075bf994
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Scenes
        CollectorGUID: b3332ee13576c994186d5570af59b0b6
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Config
        CollectorGUID: 6a0e1d814ea59174985b17c9f4ecaba3
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
@@ -76,10 +153,10 @@
      Collectors: []
  - PackageName: UIEffect
    PackageDesc: 
    EnableAddressable: 0
    EnableAddressable: 1
    SupportExtensionless: 1
    LocationToLower: 0
    IncludeAssetGUID: 0
    IncludeAssetGUID: 1
    AutoCollectShaders: 1
    IgnoreRuleName: NormalIgnoreRule
    Groups:
@@ -88,10 +165,62 @@
      AssetTags: 
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/Effect
        CollectorGUID: 63ddc4df56ae98b4cbc48f45628a26a7
      - CollectPath: Assets/ResourcesOut/UIEffect
        CollectorGUID: 62eb3abc624381e4b8950f355812a8e9
        CollectorType: 0
        AddressRuleName: AddressByFileName
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
  - PackageName: Battle
    PackageDesc: battle resources
    EnableAddressable: 1
    SupportExtensionless: 1
    LocationToLower: 0
    IncludeAssetGUID: 1
    AutoCollectShaders: 1
    IgnoreRuleName: NormalIgnoreRule
    Groups:
    - GroupName: Prefab
      GroupDesc:
      AssetTags:
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/Hero
        CollectorGUID: 4ef1d5e33efbd83438f79bd2fd7c44ac
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
      - CollectPath: Assets/ResourcesOut/Battle
        CollectorGUID: f4b5330ed101c7b4c8cbfba3f0daff9f
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
  - PackageName: Audio
    PackageDesc: audio resources
    EnableAddressable: 1
    SupportExtensionless: 1
    LocationToLower: 0
    IncludeAssetGUID: 1
    AutoCollectShaders: 1
    IgnoreRuleName: NormalIgnoreRule
    Groups:
    - GroupName: Prefab
      GroupDesc:
      AssetTags:
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/Audio
        CollectorGUID: 3d2c92bf721b286489d290a1a2c9763a
        CollectorType: 0
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
Assets/Editor/YooAsset.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5357a95619b07614a93e905607cd4533
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Editor/YooAsset/AddressByRelativePath.cs
New file
@@ -0,0 +1,43 @@
// ============================================================================
// AddressByRelativePath.cs — 自定义 YooAsset 地址规则
// 使用相对于 CollectPath 的完整路径(不含扩展名)作为地址
// 解决同 Package 内不同子目录下同名文件的地址冲突
// ============================================================================
using System.IO;
using YooAsset.Editor;
/// <summary>
/// 定位地址 = 资源相对于收集目录的路径(不含扩展名)。
/// 例如 CollectPath = "Assets/ResourcesOut/Audio"
///      AssetPath  = "Assets/ResourcesOut/Audio/Battle/Effect/boom.wav"
///      → 地址 = "Battle/Effect/boom"
/// </summary>
[DisplayName("定位地址: 相对路径")]
public class AddressByRelativePath : IAddressRule
{
    string IAddressRule.GetAssetAddress(AddressRuleData data)
    {
        // 去掉 CollectPath 前缀,得到相对路径
        string relativePath = data.AssetPath;
        string collectRoot = data.CollectPath;
        // 确保以 / 结尾
        if (!collectRoot.EndsWith("/"))
            collectRoot += "/";
        if (relativePath.StartsWith(collectRoot))
        {
            relativePath = relativePath.Substring(collectRoot.Length);
        }
        // 去掉扩展名
        string ext = Path.GetExtension(relativePath);
        if (!string.IsNullOrEmpty(ext))
        {
            relativePath = relativePath.Substring(0, relativePath.Length - ext.Length);
        }
        return relativePath;
    }
}
Assets/Editor/YooAsset/AddressByRelativePath.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b86b10bad08b3244ab4a912f2c8bdff7
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Launch/Common/IYooAssetBridge.cs
New file
@@ -0,0 +1,82 @@
// ============================================================================
// IYooAssetBridge.cs — 跨程序集资源加载桥接接口
// 定义在 Launch 程序集中,由 Main 程序集中的 YooAssetService 实现
// ============================================================================
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace ProjSG.Resource
{
    /// <summary>
    /// 跨程序集资源加载桥接接口。
    /// 定义在 Launch 程序集中,允许 Launch 代码在 Main 热更 DLL 加载后
    /// 通过该接口使用 Main 中实现的完整 YooAsset 封装。
    /// </summary>
    public interface IYooAssetBridge
    {
        /// <summary>
        /// 桥接是否已注册(Main 程序集已加载并注册实现)
        /// </summary>
        bool IsRegistered { get; }
        /// <summary>
        /// 异步加载资源。
        /// </summary>
        /// <typeparam name="T">资源类型</typeparam>
        /// <param name="location">YooAsset 资源地址</param>
        /// <returns>加载完成的资源对象</returns>
        UniTask<T> LoadAssetAsync<T>(string location) where T : UnityEngine.Object;
        /// <summary>
        /// 异步加载原始文本文件。
        /// </summary>
        /// <param name="location">YooAsset 资源地址</param>
        /// <returns>文件文本内容</returns>
        UniTask<string> LoadRawFileTextAsync(string location);
        /// <summary>
        /// 异步加载原始二进制文件。
        /// </summary>
        UniTask<byte[]> LoadRawFileBytesAsync(string location);
        /// <summary>
        /// 批量预加载资源。
        /// </summary>
        /// <param name="locations">资源地址列表</param>
        UniTask PreloadAsync(string[] locations);
        /// <summary>
        /// 同步获取已缓存的资源。
        /// 仅在资源已预加载后可用,否则返回 null。
        /// </summary>
        T GetCached<T>(string location) where T : UnityEngine.Object;
    }
    /// <summary>
    /// IYooAssetBridge 的全局注册点。
    /// Launch 程序集通过此静态类访问 Main 注册的桥接实现。
    /// </summary>
    public static class YooAssetBridgeHolder
    {
        private static IYooAssetBridge _instance;
        /// <summary>
        /// 获取已注册的桥接实例。
        /// </summary>
        public static IYooAssetBridge Instance => _instance;
        /// <summary>
        /// 注册桥接实现(由 Main 程序集在初始化时调用)。
        /// </summary>
        public static void Register(IYooAssetBridge bridge)
        {
            _instance = bridge;
        }
        /// <summary>
        /// 桥接是否已注册。
        /// </summary>
        public static bool IsRegistered => _instance != null && _instance.IsRegistered;
    }
}
Assets/Launch/Common/IYooAssetBridge.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f1ec0c19dc4344d4da9da6e52850e783
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Launch/Launch.cs
@@ -11,6 +11,7 @@
using UnityEngine.Networking;
using LaunchCommon;
using HybridCLR;
using YooAsset;
public class Launch : MonoBehaviour
{
@@ -51,7 +52,7 @@
        m_Instance = this;
#if !UNITY_EDITOR
#if !UNITY_EDITOR && !UNITY_WEBGL
        if (File.Exists(Directory.GetParent(Application.persistentDataPath) + "/Debug") ||
        LocalSave.GetString("#@#BrancH") != string.Empty)
        {
@@ -72,9 +73,48 @@
        Debug.Log("Launch Start");
        InitPlugins();
        // 1. 尽早初始化 YooAsset,确保 LocalResManager 加载资源时可使用 YooAsset
        await InitYooAssetEarlyAsync();
        InitSetting();
        // 1. 打开加载界面
    }
    /// <summary>
    /// 在 Launch 阶段尽早初始化 YooAsset。
    /// 完成后 LocalResManager.LoadSprite/LoadBuiltInPrefab 将通过 YooAsset 加载资源。
    /// </summary>
    private async UniTask InitYooAssetEarlyAsync()
    {
        try
        {
#if UNITY_EDITOR
            var playMode = EPlayMode.EditorSimulateMode;
#elif UNITY_WEBGL
            var playMode = EPlayMode.WebPlayMode;
#else
            var playMode = EPlayMode.OfflinePlayMode;
#endif
            Debug.Log($"[Launch] Initializing YooAsset early with PlayMode={playMode}");
            await YooAssetInitializer.Instance.InitializeAsync(playMode);
            if (YooAssetInitializer.Instance.State == YooAssetInitializer.InitState.InitFailed)
            {
                Debug.LogError($"[Launch] YooAsset early init failed: {YooAssetInitializer.Instance.LastError}");
                return;
            }
            // EditorSimulateMode 和 OfflinePlayMode 不需要远程版本管理,
            // 直接标记为 Ready
            await YooAssetInitializer.Instance.RequestVersionAndUpdateAsync();
            Debug.Log("[Launch] YooAsset early init completed. State: " + YooAssetInitializer.Instance.State);
        }
        catch (Exception ex)
        {
            Debug.LogError($"[Launch] YooAsset early init exception: {ex}");
        }
    }
    private void InitSetting()
@@ -203,6 +243,10 @@
            DownLoadAndDiscompressTask.Destroy();
        }
        // YooAssetInitializer 不在此处销毁 —— 其 DefaultPackage 需要保留
        // 供 Main 程序集中 YooAssetService 接管使用(通过 IYooAssetBridge)
        // YooAssetInitializer 的 Release 由 YooAssetService 初始化时决定
        if (null != launchExWin)
        {
            Destroy(launchExWin);
Assets/Launch/Manager/LocalResManager.cs
@@ -3,10 +3,12 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using System;
using System.Threading;
using UnityEngine.U2D;
using LitJson;
using System.IO;
using UnityEngine.Networking;
using YooAsset;
#if UNITY_EDITOR
using UnityEditor;
@@ -137,9 +139,18 @@
        }
    }
    [Obsolete("Legacy AB loading — use YooAsset via YooAssetInitializer")]
    private AssetBundle spriteBundle = null;   //需要卸载
    [Obsolete("Legacy AB loading — use YooAsset via YooAssetInitializer")]
    private AssetBundle prefabBundle = null;   //需要卸载
    private SpriteAtlas spriteAtlas = null;
    /// <summary>
    /// YooAsset 是否已就绪(由 YooAssetInitializer 初始化)
    /// </summary>
    private bool IsYooAssetReady => YooAssetInitializer.IsValid()
        && YooAssetInitializer.Instance.State == YooAssetInitializer.InitState.Ready
        && YooAssetInitializer.Instance.DefaultPackage != null;
    public void Init()
    {
@@ -152,6 +163,7 @@
        }
        var parentDirectory = Directory.GetParent(Application.persistentDataPath);
#if !UNITY_WEBGL
        if (File.Exists(parentDirectory + "/Debug"))
        {
            var content = File.ReadAllText(parentDirectory + "/Debug");
@@ -161,6 +173,7 @@
                debugBranch = json.branch;
            }
        }
#endif
        Clock.Init();
        Debug.Log("LocalResManager.Init");
@@ -168,8 +181,10 @@
    public void Release()
    {
#pragma warning disable CS0612, CS0618 // Suppress obsolete warnings for legacy cleanup
        spriteBundle?.Unload(true);  //true完全卸载,更新后重新加载
        prefabBundle?.Unload(true);
#pragma warning restore CS0612, CS0618
        assetVersions = null;
        localAssetVersions = null;
        spriteAtlas = null;
@@ -237,6 +252,10 @@
        return path;
    }
    /// <summary>
    /// 同步加载 Sprite。
    /// 优先使用 YooAsset(若已初始化),否则回退到传统 AssetBundle 加载。
    /// </summary>
    public Sprite LoadSprite(string name)
    {
        Sprite sprite = null;
@@ -251,15 +270,22 @@
            var spriteAtlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2");
            sprite = spriteAtlas.GetSprite(name);
        }
#else
        if (spriteBundle == null)
        if (IsYooAssetReady)
        {
            string _path = GetAssetFilePath("builtin/sprites");
            spriteBundle = AssetBundle.LoadFromFile(_path);
            var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetSync<Sprite>(name);
            sprite = handle.AssetObject as Sprite;
        }
        sprite = spriteBundle.LoadAsset(name, typeof(Sprite)) as Sprite;
        else
        {
            // Legacy fallback — AssetBundle.LoadFromFile
            if (spriteBundle == null)
            {
                string _path = GetAssetFilePath("builtin/sprites");
                spriteBundle = AssetBundle.LoadFromFile(_path);
            }
            sprite = spriteBundle.LoadAsset(name, typeof(Sprite)) as Sprite;
        }
#endif
        if (sprite == null)
        {
@@ -269,6 +295,49 @@
        return sprite;
    }
    /// <summary>
    /// 异步加载 Sprite(WebGL 兼容)。
    /// 使用 YooAsset 异步加载 API,适用于所有平台。
    /// </summary>
    public async UniTask<Sprite> LoadSpriteAsync(string name, CancellationToken cancellationToken = default)
    {
        Sprite sprite = null;
#if UNITY_EDITOR
        if (excludePngs.Contains(StringUtility.Concat(name, ".png")))
        {
            var path = StringUtility.Concat("Assets/ResourcesOut/BuiltIn/Sprites/", name, ".png");
            sprite = UnityEditor.AssetDatabase.LoadAssetAtPath<Sprite>(path);
        }
        else
        {
            var atlas = UnityEditor.AssetDatabase.LoadAssetAtPath<SpriteAtlas>("Assets/ResourcesOut/BuiltIn/Sprites/sprites.spriteatlasv2");
            sprite = atlas.GetSprite(name);
        }
#else
        if (IsYooAssetReady)
        {
            var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetAsync<Sprite>(name);
            await handle.ToUniTask(cancellationToken: cancellationToken);
            sprite = handle.AssetObject as Sprite;
        }
        else
        {
            // Fallback to sync if YooAsset not ready (should not happen in normal flow)
            Debug.LogWarning($"[LocalResManager] LoadSpriteAsync: YooAsset not ready, falling back to sync for '{name}'");
            sprite = LoadSprite(name);
        }
#endif
        if (sprite == null)
        {
            Debug.LogErrorFormat("LoadSpriteAsync() => 加载不到资源: {0}.", name);
        }
        return sprite;
    }
    /// <summary>
    /// 同步加载内置预制体。
    /// 优先使用 YooAsset(若已初始化),否则回退到传统 AssetBundle 加载。
    /// </summary>
    public GameObject LoadBuiltInPrefab(string name)
    {
        GameObject prefab = null;
@@ -276,12 +345,21 @@
        var path = string.Concat("Assets/ResourcesOut/BuiltIn/Prefabs/", name, ".prefab");
        prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path);
#else
        if (prefabBundle == null)
        if (IsYooAssetReady)
        {
            string _path = GetAssetFilePath("builtin/prefabs");
            prefabBundle = AssetBundle.LoadFromFile(_path);
            var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetSync<GameObject>(name);
            prefab = handle.AssetObject as GameObject;
        }
        prefab = prefabBundle.LoadAsset(name) as GameObject;
        else
        {
            // Legacy fallback — AssetBundle.LoadFromFile
            if (prefabBundle == null)
            {
                string _path = GetAssetFilePath("builtin/prefabs");
                prefabBundle = AssetBundle.LoadFromFile(_path);
            }
            prefab = prefabBundle.LoadAsset(name) as GameObject;
        }
#endif
        if (prefab == null)
        {
@@ -291,6 +369,36 @@
        return prefab;
    }
    /// <summary>
    /// 异步加载内置预制体(WebGL 兼容)。
    /// 使用 YooAsset 异步加载 API,适用于所有平台。
    /// </summary>
    public async UniTask<GameObject> LoadBuiltInPrefabAsync(string name, CancellationToken cancellationToken = default)
    {
        GameObject prefab = null;
#if UNITY_EDITOR
        var path = string.Concat("Assets/ResourcesOut/BuiltIn/Prefabs/", name, ".prefab");
        prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>(path);
#else
        if (IsYooAssetReady)
        {
            var handle = YooAssetInitializer.Instance.DefaultPackage.LoadAssetAsync<GameObject>(name);
            await handle.ToUniTask(cancellationToken: cancellationToken);
            prefab = handle.AssetObject as GameObject;
        }
        else
        {
            Debug.LogWarning($"[LocalResManager] LoadBuiltInPrefabAsync: YooAsset not ready, falling back to sync for '{name}'");
            prefab = LoadBuiltInPrefab(name);
        }
#endif
        if (prefab == null)
        {
            Debug.LogErrorFormat("LoadBuiltInPrefabAsync() => 加载不到资源: {0}.", name);
        }
        return prefab;
    }
    static Dictionary<string, string> languageShowDict = new Dictionary<string, string>();//射中显示的多语言版本
    Dictionary<string, string> languageDict = new Dictionary<string, string>();// unity语言配置对应的约定字符
Assets/Launch/Manager/YooAssetInitializer.cs
New file
@@ -0,0 +1,403 @@
// ============================================================================
// YooAssetInitializer.cs — Launch 阶段 YooAsset 初始化器
// 在 Launch AOT 程序集中执行 YooAsset 的包裹创建、版本请求与 Manifest 更新
// 支持 EditorSimulateMode / HostPlayMode / OfflinePlayMode / WebPlayMode
// 支持多 Package 并行初始化
// ============================================================================
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
using YooAsset;
/// <summary>
/// Launch 阶段负责 YooAsset 资源系统的早期初始化。
/// 完成 ResourcePackage 的创建、初始化参数配置、版本请求与 Manifest 更新。
/// 支持多 Package 初始化,包名须与 AssetBundleCollectorSetting 一致。
/// </summary>
public class YooAssetInitializer : Singleton<YooAssetInitializer>
{
    /// <summary>
    /// 初始化状态
    /// </summary>
    public enum InitState
    {
        Uninitialized,
        Initializing,
        Initialized,
        VersionChecked,
        Ready,
        InitFailed,
        VersionFailed,
    }
    // ====================================================================
    // Package 名称常量 — 必须与 AssetBundleCollectorSetting.asset 一致
    // Launch 程序集无法引用 Main 的 YooAssetPackageConfig,在此重复定义
    // ====================================================================
    /// <summary>默认包名 — Prefab 包含启动必需资源</summary>
    public const string DEFAULT_PACKAGE_NAME = "Prefab";
    /// <summary>
    /// Launch 阶段需要初始化的包名(与 Collector 一致)。
    /// </summary>
    private static readonly string[] LAUNCH_PACKAGES = new[] { "Prefab", "UI", "UIEffect", "Battle", "Audio" };
    private EPlayMode _playMode;
    private IRemoteServices _remoteServices;
    private ResourcePackage _defaultPackage;
    private readonly Dictionary<string, ResourcePackage> _packages = new Dictionary<string, ResourcePackage>();
    /// <summary>
    /// 当前初始化状态
    /// </summary>
    public InitState State { get; private set; } = InitState.Uninitialized;
    /// <summary>
    /// 最后一次错误信息
    /// </summary>
    public string LastError { get; private set; }
    /// <summary>
    /// 获取已初始化的默认包裹(向后兼容 LocalResManager)
    /// </summary>
    public ResourcePackage DefaultPackage => _defaultPackage;
    /// <summary>
    /// 当前运行模式
    /// </summary>
    public EPlayMode PlayMode => _playMode;
    /// <summary>
    /// 获取指定名称的已初始化包裹,找不到返回 null
    /// </summary>
    public ResourcePackage GetPackage(string packageName)
    {
        _packages.TryGetValue(packageName, out var pkg);
        return pkg;
    }
    /// <summary>
    /// 所有已成功初始化的包名
    /// </summary>
    public IEnumerable<string> InitializedPackageNames => _packages.Keys;
    // ====================================================================
    // 初始化
    // ====================================================================
    /// <summary>
    /// 初始化 YooAsset,创建并初始化多个 ResourcePackage。
    /// </summary>
    /// <param name="playMode">运行模式(EditorSimulateMode / HostPlayMode)</param>
    /// <param name="remoteServices">CDN 远程服务地址配置(HostPlayMode 必需)</param>
    /// <param name="packageNames">要初始化的包名列表,null 使用 LAUNCH_PACKAGES</param>
    public async UniTask InitializeAsync(EPlayMode playMode = EPlayMode.HostPlayMode,
        IRemoteServices remoteServices = null, string[] packageNames = null)
    {
        if (State != InitState.Uninitialized)
        {
            Debug.LogWarning($"[YooAssetInitializer] Invalid state for Initialize: {State}");
            return;
        }
        State = InitState.Initializing;
        _playMode = playMode;
        _remoteServices = remoteServices;
        var names = packageNames ?? LAUNCH_PACKAGES;
        int successCount = 0;
        try
        {
            // YooAsset 全局初始化(幂等)
            YooAssets.Initialize();
            foreach (var pkgName in names)
            {
                try
                {
                    var package = YooAssets.CreatePackage(pkgName);
                    var initParams = CreateInitParameters(playMode, remoteServices, pkgName);
                    var initOp = package.InitializeAsync(initParams);
                    await initOp.ToUniTask();
                    if (initOp.Status != EOperationStatus.Succeed)
                    {
                        Debug.LogWarning($"[YooAssetInitializer] Package '{pkgName}' init failed: {initOp.Error}");
                        continue;
                    }
                    _packages[pkgName] = package;
                    successCount++;
                    // DEFAULT_PACKAGE_NAME 或第一个成功的包作为默认包
                    if (_defaultPackage == null || pkgName == DEFAULT_PACKAGE_NAME)
                    {
                        _defaultPackage = package;
                        YooAssets.SetDefaultPackage(package);
                    }
                    Debug.Log($"[YooAssetInitializer] Package '{pkgName}' initialized.");
                }
                catch (Exception ex)
                {
                    // EditorSimulateMode 下包不在 Collector 中会抛异常,跳过即可
                    Debug.LogWarning($"[YooAssetInitializer] Package '{pkgName}' init exception (skipped): {ex.Message}");
                }
            }
            if (successCount == 0)
            {
                LastError = "No packages initialized successfully.";
                State = InitState.InitFailed;
                Debug.LogError($"[YooAssetInitializer] {LastError}");
                return;
            }
            State = InitState.Initialized;
            Debug.Log($"[YooAssetInitializer] Initialized {successCount}/{names.Length} packages with PlayMode={playMode}");
        }
        catch (Exception ex)
        {
            LastError = ex.Message;
            State = InitState.InitFailed;
            Debug.LogError($"[YooAssetInitializer] Initialize exception: {ex}");
        }
    }
    // ====================================================================
    // 版本管理
    // ====================================================================
    /// <summary>
    /// 请求最新版本号并更新 Manifest(对所有已初始化的包裹)。
    /// 仅在 HostPlayMode 下有意义,EditorSimulateMode / OfflinePlayMode 下跳过。
    /// </summary>
    public async UniTask RequestVersionAndUpdateAsync()
    {
        if (State != InitState.Initialized)
        {
            Debug.LogWarning($"[YooAssetInitializer] Invalid state for RequestVersionAndUpdate: {State}");
            return;
        }
        // EditorSimulateMode / OfflinePlayMode 不需要远程版本管理
        if (_playMode == EPlayMode.EditorSimulateMode || _playMode == EPlayMode.OfflinePlayMode)
        {
            State = InitState.VersionChecked;
            State = InitState.Ready;
            Debug.Log("[YooAssetInitializer] Skipped version check (local mode). State → Ready");
            return;
        }
        try
        {
            foreach (var kvp in _packages)
            {
                var pkgName = kvp.Key;
                var package = kvp.Value;
                // 1. 请求版本号
                var versionOp = package.RequestPackageVersionAsync();
                await versionOp.ToUniTask();
                if (versionOp.Status != EOperationStatus.Succeed)
                {
                    Debug.LogWarning($"[YooAssetInitializer] RequestPackageVersion failed for '{pkgName}': {versionOp.Error}");
                    continue;
                }
                string packageVersion = versionOp.PackageVersion;
                Debug.Log($"[YooAssetInitializer] Package '{pkgName}' version: {packageVersion}");
                // 2. 更新 Manifest
                var manifestOp = package.UpdatePackageManifestAsync(packageVersion);
                await manifestOp.ToUniTask();
                if (manifestOp.Status != EOperationStatus.Succeed)
                {
                    Debug.LogWarning($"[YooAssetInitializer] UpdatePackageManifest failed for '{pkgName}': {manifestOp.Error}");
                    continue;
                }
                Debug.Log($"[YooAssetInitializer] Package '{pkgName}' manifest updated to {packageVersion}.");
            }
            State = InitState.VersionChecked;
            State = InitState.Ready;
            Debug.Log("[YooAssetInitializer] All packages version checked. State → Ready");
        }
        catch (Exception ex)
        {
            LastError = ex.Message;
            State = InitState.VersionFailed;
            Debug.LogError($"[YooAssetInitializer] Version update exception: {ex}");
        }
    }
    // ====================================================================
    // 下载器创建
    // ====================================================================
    /// <summary>
    /// 创建资源下载器,用于下载指定标签的远程资源。
    /// </summary>
    /// <param name="tags">资源标签数组</param>
    /// <param name="downloadingMaxNumber">同时下载最大数量</param>
    /// <param name="failedTryAgain">失败重试次数</param>
    /// <param name="packageName">指定包名,null 则使用默认包</param>
    /// <returns>下载器操作句柄</returns>
    public ResourceDownloaderOperation CreateDownloader(string[] tags,
        int downloadingMaxNumber = 10, int failedTryAgain = 3, string packageName = null)
    {
        if (State < InitState.Ready)
        {
            Debug.LogError($"[YooAssetInitializer] Cannot create downloader in state: {State}");
            return null;
        }
        var package = _defaultPackage;
        if (!string.IsNullOrEmpty(packageName) && _packages.TryGetValue(packageName, out var target))
        {
            package = target;
        }
        // 多标签合并下载器
        if (tags == null || tags.Length == 0)
        {
            return package.CreateResourceDownloader(downloadingMaxNumber, failedTryAgain);
        }
        if (tags.Length == 1)
        {
            return package.CreateResourceDownloader(tags[0], downloadingMaxNumber, failedTryAgain);
        }
        // 多个标签使用第一个标签创建下载器(YooAsset 2.x 不支持多标签合并创建)
        return package.CreateResourceDownloader(tags[0], downloadingMaxNumber, failedTryAgain);
    }
    /// <summary>
    /// 执行下载操作并等待完成。
    /// </summary>
    public async UniTask DownloadAsync(ResourceDownloaderOperation downloader,
        IProgress<float> progress = null)
    {
        if (downloader == null)
        {
            Debug.LogWarning("[YooAssetInitializer] Downloader is null.");
            return;
        }
        if (downloader.TotalDownloadCount == 0)
        {
            Debug.Log("[YooAssetInitializer] No resources need to download.");
            progress?.Report(1f);
            return;
        }
        Debug.Log($"[YooAssetInitializer] Start downloading {downloader.TotalDownloadCount} files, total {downloader.TotalDownloadBytes} bytes");
        downloader.BeginDownload();
        while (!downloader.IsDone)
        {
            progress?.Report(downloader.Progress);
            await UniTask.Yield();
        }
        if (downloader.Status != EOperationStatus.Succeed)
        {
            Debug.LogError($"[YooAssetInitializer] Download failed: {downloader.Error}");
            throw new InvalidOperationException($"Resource download failed: {downloader.Error}");
        }
        progress?.Report(1f);
        Debug.Log("[YooAssetInitializer] Download completed.");
    }
    // ====================================================================
    // 辅助方法
    // ====================================================================
    private InitializeParameters CreateInitParameters(EPlayMode playMode, IRemoteServices remoteServices, string packageName)
    {
        switch (playMode)
        {
            case EPlayMode.EditorSimulateMode:
            {
#if UNITY_EDITOR
                var simulateResult = EditorSimulateModeHelper.SimulateBuild(packageName);
                return new EditorSimulateModeParameters
                {
                    EditorFileSystemParameters = FileSystemParameters
                        .CreateDefaultEditorFileSystemParameters(simulateResult.PackageRootDirectory)
                };
#else
                throw new InvalidOperationException("EditorSimulateMode is only available in Unity Editor.");
#endif
            }
            case EPlayMode.HostPlayMode:
            {
                return new HostPlayModeParameters
                {
                    BuildinFileSystemParameters = FileSystemParameters
                        .CreateDefaultBuildinFileSystemParameters(),
                    CacheFileSystemParameters = FileSystemParameters
                        .CreateDefaultCacheFileSystemParameters(remoteServices)
                };
            }
            case EPlayMode.OfflinePlayMode:
            {
                return new OfflinePlayModeParameters
                {
                    BuildinFileSystemParameters = FileSystemParameters
                        .CreateDefaultBuildinFileSystemParameters()
                };
            }
            case EPlayMode.WebPlayMode:
            {
                var webParams = new WebPlayModeParameters();
#if UNITY_WEBGL && WEIXINMINIGAME && !UNITY_EDITOR
                // 微信小游戏:使用 WechatFileSystem 进行资源缓存
                string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE";
                webParams.WebServerFileSystemParameters = WechatFileSystemCreater
                    .CreateFileSystemParameters(packageRoot, remoteServices);
#elif UNITY_WEBGL && DOUYINMINIGAME && !UNITY_EDITOR
                // 抖音小游戏:使用 TiktokFileSystem 进行资源缓存
                string packageRoot = TTSDK.TTFileSystem.USER_DATA_PATH + "/__GAME_FILE_CACHE";
                webParams.WebServerFileSystemParameters = TiktokFileSystemCreater
                    .CreateFileSystemParameters(packageRoot, remoteServices);
#else
                // 默认 WebGL:使用标准 WebServer 文件系统
                webParams.WebServerFileSystemParameters = FileSystemParameters
                    .CreateDefaultWebServerFileSystemParameters();
                if (remoteServices != null)
                {
                    webParams.WebRemoteFileSystemParameters = FileSystemParameters
                        .CreateDefaultWebRemoteFileSystemParameters(remoteServices);
                }
#endif
                return webParams;
            }
            default:
                throw new ArgumentOutOfRangeException(nameof(playMode), playMode, "Unsupported PlayMode.");
        }
    }
    /// <summary>
    /// 释放资源,重置状态。
    /// </summary>
    public void Release()
    {
        _defaultPackage = null;
        _packages.Clear();
        _remoteServices = null;
        LastError = null;
        State = InitState.Uninitialized;
    }
}
Assets/Launch/Manager/YooAssetInitializer.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fd8ad00c7c0e32543a87d5a6fd048067
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Launch/UI/LaunchWins/LaunchExWin.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
using LaunchCommon;
public class LaunchExWin : MonoBehaviour
@@ -36,11 +37,35 @@
        // m_BackGround.overrideSprite = sprite;
        // m_BackGround.preserveAspect = true;
        sliderText = InitialFunctionConfig.Get("Language").Numerical3;
        // 同步加载保留(YooAsset 初始化后走 YooAsset sync API,否则走 legacy AB)
        imagebg1.sprite = LocalResManager.Instance.LoadSprite("TY_TB_JH1");
        imagebg2.sprite = LocalResManager.Instance.LoadSprite("TY_TB_JH1");
        imageCircle.sprite = LocalResManager.Instance.LoadSprite("TY_TB_JH2");
        imagebg3.sprite = LocalResManager.Instance.LoadSprite("LoadingBottom");
        imageloding.sprite = LocalResManager.Instance.LoadSprite("LoadingSlider");
    }
    /// <summary>
    /// 异步初始化 Launch 界面精灵(WebGL 兼容)。
    /// 在 OpenWindowAsync 中调用,Awake 中的同步加载仅作后备。
    /// </summary>
    public async UniTask InitSpritesAsync()
    {
        sliderText = InitialFunctionConfig.Get("Language").Numerical3;
        var sprites = await UniTask.WhenAll(
            LocalResManager.Instance.LoadSpriteAsync("TY_TB_JH1"),
            LocalResManager.Instance.LoadSpriteAsync("TY_TB_JH2"),
            LocalResManager.Instance.LoadSpriteAsync("LoadingBottom"),
            LocalResManager.Instance.LoadSpriteAsync("LoadingSlider")
        );
        if (this == null) return; // destroyed check after await
        imagebg1.sprite = sprites.Item1;
        imagebg2.sprite = sprites.Item1;
        imageCircle.sprite = sprites.Item2;
        imagebg3.sprite = sprites.Item3;
        imageloding.sprite = sprites.Item4;
    }
    private void OnEnable()
@@ -134,4 +159,30 @@
        window.transform.localScale = Vector3.zero;
        return window;
    }
    /// <summary>
    /// 异步打开 Launch 窗口(WebGL 兼容)。
    /// 通过 YooAsset 异步加载预制体和精灵,适用于所有平台。
    /// </summary>
    public static async UniTask<GameObject> OpenWindowAsync()
    {
        var prefab = await LocalResManager.Instance.LoadBuiltInPrefabAsync("LaunchExWin");
        if (prefab == null)
        {
            Debug.LogError("[LaunchExWin] Failed to load LaunchExWin prefab asynchronously.");
            return null;
        }
        GameObject window = GameObject.Instantiate(prefab);
        window.transform.localScale = Vector3.zero;
        // 异步加载精灵
        var launchWin = window.GetComponent<LaunchExWin>();
        if (launchWin != null)
        {
            await launchWin.InitSpritesAsync();
        }
        return window;
    }
}
Assets/Plugins/YooAsset.MiniGame.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 448a76f35c893fb4598fda8d52e76a58
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.MiniGame/README.md
New file
@@ -0,0 +1,31 @@
# YooAsset Mini Game File Systems
此目录包含小游戏平台专用的 YooAsset 文件系统实现。
## 导入说明
从 YooAsset 2.3.15 的 Samples~ 目录按需复制对应平台的实现:
```
Library/PackageCache/com.tuyoogame.yooasset@2.3.15/Samples~/Mini Game/Runtime/
├── WechatFileSystem/    → 复制到 Assets/Plugins/YooAsset.MiniGame/WechatFileSystem/
├── TiktokFileSystem/    → 复制到 Assets/Plugins/YooAsset.MiniGame/TiktokFileSystem/
└── YooAsset.MiniGame.asmdef
```
## 平台编译宏
- **微信小游戏**: `UNITY_WEBGL && WEIXINMINIGAME`
- **抖音小游戏**: `UNITY_WEBGL && DOUYINMINIGAME`
## 文件系统缓存路径
| 平台 | 缓存根路径 |
|------|-----------|
| 微信 | `WX.env.USER_DATA_PATH/__GAME_FILE_CACHE` |
| 抖音 | `TTFileSystem.USER_DATA_PATH/__GAME_FILE_CACHE` |
## 使用方式
在 `YooAssetInitializer.CreateInitParameters` 和 `YooAssetService.CreateInitParameters` 中已集成。
当检测到对应平台宏时,会自动使用对应的文件系统创建器。
Assets/Plugins/YooAsset.MiniGame/README.md.meta
New file
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fc233d1ce92f8164abbd31509b132529
TextScriptImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2be0d63fc0ca312459c0d0c4a802efe2
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/Runtime.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 448d43cd584a196498dedf8c0e71153f
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/Runtime/External.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7349d92658667a446946561d5ec25189
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 01c8f5fcda5fc6742b9c202dbd83146c
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/AsyncOperationBaseExtensions.cs
New file
@@ -0,0 +1,125 @@
#if UNITASK_YOOASSET_SUPPORT
using System;
using YooAsset;
using static Cysharp.Threading.Tasks.Internal.Error;
namespace Cysharp.Threading.Tasks
{
    public static class AsyncOperationBaseExtensions
    {
        public static UniTask.Awaiter GetAwaiter(this AsyncOperationBase handle)
        {
            return ToUniTask(handle).GetAwaiter();
        }
        public static UniTask ToUniTask(this AsyncOperationBase handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update)
        {
            ThrowArgumentNullException(handle, nameof(handle));
            if (handle.IsDone)
            {
                return UniTask.CompletedTask;
            }
            return new UniTask(
                AsyncOperationBaserConfiguredSource.Create(handle, timing, progress, out var token),
                token
            );
        }
        sealed class AsyncOperationBaserConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationBaserConfiguredSource>
        {
            private static TaskPool<AsyncOperationBaserConfiguredSource> _pool;
            private AsyncOperationBaserConfiguredSource _nextNode;
            private readonly Action<AsyncOperationBase> _continuationAction;
            private AsyncOperationBase _handle;
            private IProgress<float> _progress;
            private bool _completed;
            private UniTaskCompletionSourceCore<AsyncUnit> _core;
            public ref AsyncOperationBaserConfiguredSource NextNode => ref _nextNode;
            static AsyncOperationBaserConfiguredSource()
            {
                TaskPool.RegisterSizeGetter(typeof(AsyncOperationBaserConfiguredSource), () => _pool.Size);
            }
            AsyncOperationBaserConfiguredSource() { _continuationAction = Continuation; }
            public static IUniTaskSource Create(AsyncOperationBase handle, PlayerLoopTiming timing, IProgress<float> progress, out short token)
            {
                if (!_pool.TryPop(out var result))
                {
                    result = new AsyncOperationBaserConfiguredSource();
                }
                result._handle = handle;
                result._progress = progress;
                result._completed = false;
                TaskTracker.TrackActiveTask(result, 3);
                if (progress != null)
                {
                    PlayerLoopHelper.AddAction(timing, result);
                }
                handle.Completed += result._continuationAction;
                token = result._core.Version;
                return result;
            }
            private void Continuation(AsyncOperationBase _)
            {
                _handle.Completed -= _continuationAction;
                if (_completed)
                {
                    TryReturn();
                }
                else
                {
                    _completed = true;
                    if (_handle.Status == EOperationStatus.Failed)
                    {
                        _core.TrySetException(new Exception(_handle.Error));
                    }
                    else
                    {
                        _core.TrySetResult(AsyncUnit.Default);
                    }
                }
            }
            private bool TryReturn()
            {
                TaskTracker.RemoveTracking(this);
                _core.Reset();
                _handle = default;
                _progress = default;
                return _pool.TryPush(this);
            }
            public UniTaskStatus GetStatus(short token) => _core.GetStatus(token);
            public void OnCompleted(Action<object> continuation, object state, short token)
            {
                _core.OnCompleted(continuation, state, token);
            }
            public void GetResult(short token) { _core.GetResult(token); }
            public UniTaskStatus UnsafeGetStatus() => _core.UnsafeGetStatus();
            public bool MoveNext()
            {
                if (_completed)
                {
                    TryReturn();
                    return false;
                }
                if (!_handle.IsDone)
                {
                    _progress?.Report(_handle.Progress);
                }
                return true;
            }
        }
    }
}
#endif
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/AsyncOperationBaseExtensions.cs.meta
New file
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2cceff5ec1f84bd0a6a9b4ed7719527c
timeCreated: 1651978895
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/OperationHandleBaseExtensions.cs
New file
@@ -0,0 +1,221 @@
#if UNITASK_YOOASSET_SUPPORT
#if UNITY_2020_1_OR_NEWER && ! UNITY_2021
#define UNITY_2020_BUG
#endif
using System;
using System.Runtime.CompilerServices;
using YooAsset;
using static Cysharp.Threading.Tasks.Internal.Error;
namespace Cysharp.Threading.Tasks
{
    public static class HandleBaseExtensions
    {
        public static UniTask.Awaiter GetAwaiter(this HandleBase handle)
        {
            return ToUniTask(handle).GetAwaiter();
        }
        public static UniTask ToUniTask(this HandleBase handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update)
        {
            ThrowArgumentNullException(handle, nameof(handle));
            if (!handle.IsValid)
            {
                return UniTask.CompletedTask;
            }
            return new UniTask(
                HandleBaserConfiguredSource.Create(handle, timing, progress, out var token),
                token
            );
        }
        sealed class HandleBaserConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<HandleBaserConfiguredSource>
        {
            private static TaskPool<HandleBaserConfiguredSource> _pool;
            private HandleBaserConfiguredSource _nextNode;
            private readonly Action<HandleBase> _continuationAction;
            private HandleBase _handle;
            private IProgress<float> _progress;
            private bool _completed;
            private UniTaskCompletionSourceCore<AsyncUnit> _core;
            public ref HandleBaserConfiguredSource NextNode => ref _nextNode;
            static HandleBaserConfiguredSource()
            {
                TaskPool.RegisterSizeGetter(typeof(HandleBaserConfiguredSource), () => _pool.Size);
            }
            HandleBaserConfiguredSource() { _continuationAction = Continuation; }
            public static IUniTaskSource Create(HandleBase handle, PlayerLoopTiming timing, IProgress<float> progress, out short token)
            {
                if (!_pool.TryPop(out var result))
                {
                    result = new HandleBaserConfiguredSource();
                }
                result._handle = handle;
                result._progress = progress;
                result._completed = false;
                TaskTracker.TrackActiveTask(result, 3);
                if (progress != null)
                {
                    PlayerLoopHelper.AddAction(timing, result);
                }
                // BUG 在 Unity 2020.3.36 版本测试中, IL2Cpp 会报 如下错误
                // BUG ArgumentException: Incompatible Delegate Types. First is System.Action`1[[YooAsset.AssetHandle, YooAsset, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]] second is System.Action`1[[YooAsset.OperationHandleBase, YooAsset, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]]
                // BUG 也可能报的是 Action '1' Action '1' 的 InvalidCastException
                // BUG 此处不得不这么修改, 如果后续 Unity 修复了这个问题, 可以恢复之前的写法
#if UNITY_2020_BUG
                switch (handle)
                {
                    case AssetHandle asset_handle:
                        asset_handle.Completed += result.AssetContinuation;
                        break;
                    case SceneHandle scene_handle:
                        scene_handle.Completed += result.SceneContinuation;
                        break;
                    case SubAssetsHandle sub_asset_handle:
                        sub_asset_handle.Completed += result.SubContinuation;
                        break;
                    case RawFileHandle raw_file_handle:
                        raw_file_handle.Completed += result.RawFileContinuation;
                        break;
                    case AllAssetsHandle all_assets_handle:
                        all_assets_handle.Completed += result.AllAssetsContinuation;
                        break;
                }
#else
                switch (handle)
                {
                    case AssetHandle asset_handle:
                        asset_handle.Completed += result.continuationAction;
                        break;
                    case SceneHandle scene_handle:
                        scene_handle.Completed += result.continuationAction;
                        break;
                    case SubAssetsHandle sub_asset_handle:
                        sub_asset_handle.Completed += result.continuationAction;
                        break;
                    case RawFileHandle raw_file_handle:
                        raw_file_handle.Completed += result.continuationAction;
                        break;
                    case AllAssetsHandle all_assets_handle:
                        all_assets_handle.Completed += result.continuationAction;
                        break;
                }
#endif
                token = result._core.Version;
                return result;
            }
#if UNITY_2020_BUG
            private void AssetContinuation(AssetHandle handle)
            {
                handle.Completed -= AssetContinuation;
                BaseContinuation();
            }
            private void SceneContinuation(SceneHandle handle)
            {
                handle.Completed -= SceneContinuation;
                BaseContinuation();
            }
            private void SubContinuation(SubAssetsHandle handle)
            {
                handle.Completed -= SubContinuation;
                BaseContinuation();
            }
            private void RawFileContinuation(RawFileHandle handle)
            {
                handle.Completed -= RawFileContinuation;
                BaseContinuation();
            }
            private void AllAssetsContinuation(AllAssetsHandle handle)
            {
                handle.Completed -= AllAssetsContinuation;
                BaseContinuation();
            }
#endif
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            private void BaseContinuation()
            {
                if (_completed)
                {
                    TryReturn();
                }
                else
                {
                    _completed = true;
                    if (_handle.Status == EOperationStatus.Failed)
                    {
                        _core.TrySetException(new Exception(_handle.LastError));
                    }
                    else
                    {
                        _core.TrySetResult(AsyncUnit.Default);
                    }
                }
            }
            private void Continuation(HandleBase _)
            {
                switch (_handle)
                {
                    case AssetHandle asset_handle:
                        asset_handle.Completed -= _continuationAction;
                        break;
                    case SceneHandle scene_handle:
                        scene_handle.Completed -= _continuationAction;
                        break;
                    case SubAssetsHandle sub_asset_handle:
                        sub_asset_handle.Completed -= _continuationAction;
                        break;
                    case RawFileHandle raw_file_handle:
                        raw_file_handle.Completed -= _continuationAction;
                        break;
                    case AllAssetsHandle all_assets_handle:
                        all_assets_handle.Completed -= _continuationAction;
                        break;
                }
                BaseContinuation();
            }
            private bool TryReturn()
            {
                TaskTracker.RemoveTracking(this);
                _core.Reset();
                _handle = default;
                _progress = default;
                return _pool.TryPush(this);
            }
            public UniTaskStatus GetStatus(short token) => _core.GetStatus(token);
            public void OnCompleted(Action<object> continuation, object state, short token)
            {
                _core.OnCompleted(continuation, state, token);
            }
            public void GetResult(short token) { _core.GetResult(token); }
            public UniTaskStatus UnsafeGetStatus() => _core.UnsafeGetStatus();
            public bool MoveNext()
            {
                if (_completed)
                {
                    TryReturn();
                    return false;
                }
                if (_handle.IsValid)
                {
                    _progress?.Report(_handle.Progress);
                }
                return true;
            }
        }
    }
}
#endif
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/OperationHandleBaseExtensions.cs.meta
New file
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e1c9a3a6de2246bf88547a6b59b99b9f
timeCreated: 1650851321
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/UniTask.YooAsset.asmdef
New file
@@ -0,0 +1,23 @@
{
    "name": "UniTask.YooAsset",
    "rootNamespace": "",
    "references": [
        "GUID:f51ebe6a0ceec4240a699833d6309b23",
        "GUID:e34a5702dd353724aa315fb8011f08c3"
    ],
    "includePlatforms": [],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": false,
    "precompiledReferences": [],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [
        {
            "name": "com.cysharp.unitask",
            "expression": "",
            "define": "UNITASK_YOOASSET_SUPPORT"
        }
    ],
    "noEngineReferences": false
}
Assets/Plugins/YooAsset.UniTask/Runtime/External/YooAsset/UniTask.YooAsset.asmdef.meta
New file
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1278a46ce459c5a46b4eaeda148684ef
AssemblyDefinitionImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/UniTaskRef.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9a37bcddb33f328418a9c5eaa682e6dd
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/UniTaskRef/UniTaskRef.asmref
New file
@@ -0,0 +1,3 @@
{
    "reference": "GUID:f51ebe6a0ceec4240a699833d6309b23"
}
Assets/Plugins/YooAsset.UniTask/UniTaskRef/UniTaskRef.asmref.meta
New file
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: fb1a9972a41e10f40a752774a402830a
AssemblyDefinitionReferenceImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Assets/Plugins/YooAsset.UniTask/UniTaskRef/_InternalVisibleTo.cs
New file
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("UniTask.YooAsset")]
Assets/Plugins/YooAsset.UniTask/UniTaskRef/_InternalVisibleTo.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc0f48d84ee89ad499856840eea08a64
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant: