Sfoglia il codice sorgente

调整代码 修复bug 同步改异步

hexiaojie 8 mesi fa
parent
commit
97996f34f5

+ 67 - 1
GameClient/Assets/Game/HotUpdate/Assets/PrefabManager.cs

@@ -1,4 +1,5 @@
-using GFGGame.Launcher;
+using System;
+using GFGGame.Launcher;
 using UniFramework.Pooling;
 using UnityEngine;
 using YooAsset;
@@ -52,6 +53,71 @@ namespace GFGGame
             return handle.GameObj;
         }
 
+        public void SpawnAsync(string resPath, Action<GameObject> callback)
+        {
+            var t = GetPreDrawObj(resPath);
+            if (t != null)
+            {
+                callback?.Invoke(t);
+                return;
+            }
+
+            if (!YooAssets.CheckResExist(resPath))
+            {
+                callback?.Invoke(null);
+                return;
+            }
+
+            // 检查对象池是否已存在
+            if (!_entitySpawner.IsGameObjectPoolExisted(resPath))
+            {
+                // 异步创建对象池
+                var createPoolHandle = _entitySpawner.CreateGameObjectPoolAsync(resPath, false, 0, 10, 60);
+                createPoolHandle.Completed += (op) =>
+                {
+                    if (op.Status == EOperationStatus.Succeed)
+                    {
+                        SpawnAfterPoolReady(resPath, callback);
+                    }
+                    else
+                    {
+                        callback?.Invoke(null);
+                    }
+                };
+            }
+            else
+            {
+                SpawnAfterPoolReady(resPath, callback);
+            }
+        }
+
+        private void SpawnAfterPoolReady(string resPath, Action<GameObject> callback)
+        {
+            var spawnHandle = _entitySpawner.SpawnAsync(resPath);
+            spawnHandle.Completed += (op) =>
+            {
+                if (op.Status == EOperationStatus.Succeed)
+                {
+                    // 需要将 AsyncOperationBase 转换为具体的 SpawnHandle
+                    if (op is SpawnHandle handle && handle.IsDone)
+                    {
+                        Log.Debug(resPath);
+                        AssetReleaserHelper.AddReleaserToSpawnObj(handle.GameObj, resPath, handle);
+                        callback?.Invoke(handle.GameObj);
+                    }
+                    else
+                    {
+                        callback?.Invoke(null);
+                    }
+                }
+                else
+                {
+                    callback?.Invoke(null);
+                }
+            };
+        }
+
+
         //public async Task<GameObject> SpawnAsync(string resPath)
         //{
         //    if (!_entitySpawner.IsGameObjectPoolExisted(resPath))

+ 50 - 11
GameClient/Assets/Game/HotUpdate/Assets/SpriteHelper.cs

@@ -1,35 +1,74 @@
 using UnityEngine;
 using YooAsset;
+using System;
 
 namespace GFGGame
 {
     public static class SpriteHelper
     {
         /// <summary>
-        /// 移除的时候请用RemoveSpriteFrom,否则不会释放资源
+        /// 异步加载图片并设置到SpriteRenderer
         /// </summary>
-        /// <param name="spr"></param>
-        /// <param name="resPath"></param>
+        /// <param name="spr">目标SpriteRenderer</param>
+        /// <param name="resPath">资源路径</param>
         public static async void AddSpriteTo(SpriteRenderer spr, string resPath)
         {
             RemoveSpriteFrom(spr);
             await LoadManager.Instance.CheckResExsitedOrDownload(resPath);
-            var handle = YooAssets.LoadAssetSync<Sprite>(resPath);
-            Sprite sp = handle.AssetObject as Sprite;
-            GameObject gameObject = spr.gameObject;
-            AssetReleaserHelper.AddReleaserToInstantiateObj(gameObject, resPath, handle);
-            spr.sprite = sp;
+
+            // 改为异步加载
+            var handle = YooAssets.LoadAssetAsync<Sprite>(resPath);
+            handle.Completed += (operation) =>
+            {
+                if (operation.Status == EOperationStatus.Succeed)
+                {
+                    Sprite sp = operation.AssetObject as Sprite;
+                    GameObject gameObject = spr.gameObject;
+                    AssetReleaserHelper.AddReleaserToInstantiateObj(gameObject, resPath, handle);
+                    spr.sprite = sp;
+                }
+                else
+                {
+                    Debug.LogError($"加载图片失败: {resPath}");
+                }
+            };
+        }
+
+        public static void AddSpriteToAsync(SpriteRenderer spr, string resPath, Action onComplete)
+        {
+            if (!YooAssets.CheckResExist(resPath))
+            {
+                Debug.LogError($"Sprite resource not found: {resPath}");
+                onComplete?.Invoke();
+                return;
+            }
+
+            var handle = YooAssets.LoadAssetAsync<Sprite>(resPath);
+            handle.Completed += (operation) =>
+            {
+                if (operation.Status == EOperationStatus.Succeed)
+                {
+                    spr.sprite = operation.AssetObject as Sprite;
+                }
+                else
+                {
+                    Debug.LogError($"Failed to load sprite: {resPath}");
+                }
+
+                operation.Release();
+                onComplete?.Invoke();
+            };
         }
 
         public static void RemoveSpriteFrom(SpriteRenderer spr)
         {
             spr.sprite = null;
-            AssetReleaser assetReleaser =  spr.gameObject.GetComponent<AssetReleaser>();
-            if(assetReleaser != null)
+            AssetReleaser assetReleaser = spr.gameObject.GetComponent<AssetReleaser>();
+            if (assetReleaser != null)
             {
                 //必须立即销毁,不能改为Destroy代替
                 GameObject.DestroyImmediate(assetReleaser);
             }
         }
     }
-}
+}

+ 38 - 19
GameClient/Assets/Game/HotUpdate/Data/DecomposeDataManager.cs

@@ -6,18 +6,20 @@ namespace GFGGame
 {
     public class DecomposeDataManager : SingletonBase<DecomposeDataManager>
     {
-        Dictionary<int, List<int>> _decomposeData = new Dictionary<int, List<int>>();//所有可分解的换装部件数据
-        Dictionary<int, List<int>> _decomposeMaterialData = new Dictionary<int, List<int>>();//所有可分解的材料数据
-        Dictionary<int, List<int>> _suitSyntheticMaterials = new Dictionary<int, List<int>>();//materiasId,Lsit<suitId>
+        Dictionary<int, List<int>> _decomposeData = new Dictionary<int, List<int>>(); //所有可分解的换装部件数据
+        Dictionary<int, List<int>> _decomposeMaterialData = new Dictionary<int, List<int>>(); //所有可分解的材料数据
+        Dictionary<int, List<int>> _suitSyntheticMaterials = new Dictionary<int, List<int>>(); //materiasId,Lsit<suitId>
         List<int> _rewardList = new List<int>();
 
         public const int MaxCount = 999;
+
         public void Clear()
         {
             _decomposeData.Clear();
             _decomposeMaterialData.Clear();
             _suitSyntheticMaterials.Clear();
         }
+
         public void Add(int itemId)
         {
             //初始化时禁止使用物品配置,会造成卡顿!!!
@@ -35,14 +37,17 @@ namespace GFGGame
 
             //套装拥有的时候需要让材料重新加进列表
             IList<ItemParamProto> syntheticMateriarsArr = ItemDataManager.GetItemSyntheticSuitArr(itemId);
-            if (syntheticMateriarsArr.Count > 0) {
+            if (syntheticMateriarsArr.Count > 0)
+            {
                 foreach (var materiars in syntheticMateriarsArr)
                 {
                     int materialId = materiars.ItemId;
                     int materialItemType = ItemDataManager.GetItemType(materialId);
-                    if (materialItemType == ConstItemType.DRESS_UP) { 
+                    if (materialItemType == ConstItemType.DRESS_UP)
+                    {
                         long materiarsCount = ItemCanDecomposeCount(materialId);
-                        if (materiarsCount> 0 && (materiarsCount + materiars.Count - DeductSynthesisNeedNum(materialId)) > 0)
+                        if (materiarsCount > 0 &&
+                            (materiarsCount + materiars.Count - DeductSynthesisNeedNum(materialId)) > 0)
                         {
                             rarity = ItemDataManager.GetItemRarity(materialId);
                             if (!_decomposeData.ContainsKey(rarity))
@@ -68,6 +73,7 @@ namespace GFGGame
             {
                 _decomposeMaterialData.Add(rarity, new List<int>());
             }
+
             if (_decomposeMaterialData[rarity].IndexOf(itemId) < 0)
             {
                 _decomposeMaterialData[rarity].Add(itemId);
@@ -90,7 +96,8 @@ namespace GFGGame
             int rarity = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemId).Rarity;
             long count = ItemCanDecomposeMaterialCount(itemId);
 
-            if (_decomposeMaterialData.ContainsKey(rarity) && _decomposeMaterialData[rarity].IndexOf(itemId) >= 0 && count <= 0)
+            if (_decomposeMaterialData.ContainsKey(rarity) && _decomposeMaterialData[rarity].IndexOf(itemId) >= 0 &&
+                count <= 0)
             {
                 _decomposeMaterialData[rarity].Remove(itemId);
             }
@@ -106,15 +113,17 @@ namespace GFGGame
             int sum = 0;
             foreach (int syntheticId in itemCfg.SyntheticSuit)
             {
-                if (ItemDataManager.GetItemNum(syntheticId) <= 0) { 
+                if (ItemDataManager.GetItemNum(syntheticId) <= 0)
+                {
                     ItemCfg syntheticItemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(syntheticId);
                     foreach (var MateriarsInfo in syntheticItemCfg.SyntheticMateriars)
                     {
-                        if(MateriarsInfo.ItemId == itemId)
+                        if (MateriarsInfo.ItemId == itemId)
                             sum += MateriarsInfo.Count;
-                    }  
+                    }
                 }
             }
+
             return sum;
         }
 
@@ -122,7 +131,7 @@ namespace GFGGame
         {
             if (_rewardList.Count == 0)
             {
-                var cfgs = CommonDataManager.Tables.TblDecomposeCfg.DataList ;
+                var cfgs = CommonDataManager.Tables.TblDecomposeCfg.DataList;
                 for (int i = 0; i < cfgs.Count; i++)
                 {
                     for (int j = 0; j < cfgs[i].Items.Count; j++)
@@ -134,13 +143,15 @@ namespace GFGGame
                     }
                 }
             }
+
             return _rewardList;
         }
 
         //物品可分解的数量
         public long CanDecomposeCount(int decomposeType, int itemId)
         {
-            if (decomposeType == 0) {
+            if (decomposeType == 0)
+            {
                 return ItemCanDecomposeCount(itemId);
             }
             else
@@ -178,7 +189,8 @@ namespace GFGGame
 
             foreach (var info in BagDataManager.Instance.GetBagData())
             {
-                if (info.Value.itemType == ConstItemType.ITEM && info.Value.subType == ConstItemSubType.MATERIAL_SKILL_BOOK)
+                if (info.Value.itemType == ConstItemType.ITEM &&
+                    info.Value.subType == ConstItemSubType.MATERIAL_SKILL_BOOK)
                 {
                     AddMaterial(info.Value.id);
                 }
@@ -205,10 +217,11 @@ namespace GFGGame
 
             for (int i = 0; i < materialDataKey.Count; i++)
             {
-                for (int k = _decomposeMaterialData[materialDataKey[i]].Count-1; k >= 0; k--)
+                for (int k = _decomposeMaterialData[materialDataKey[i]].Count - 1; k >= 0; k--)
                 {
                     int itemId = _decomposeMaterialData[materialDataKey[i]][k];
-                    if (ItemCanDecomposeMaterialCount(itemId) <= 0) {
+                    if (ItemCanDecomposeMaterialCount(itemId) <= 0)
+                    {
                         _decomposeMaterialData[materialDataKey[i]].RemoveAt(k);
                     }
                 }
@@ -222,10 +235,11 @@ namespace GFGGame
         {
             int sum = 0;
             int skillId = ItemDataManager.GetItemSkillId(itemId);
-            if(skillId == 0)
+            if (skillId == 0)
             {
                 return 0;
             }
+
             Dictionary<int, int> leagueSkillLvDatas = SkillDataManager.Instance.GetLeagueSkillLvDatas();
             if (!leagueSkillLvDatas.ContainsKey(skillId))
                 return 0;
@@ -236,17 +250,18 @@ namespace GFGGame
 
             while (skillLvlCfg != null && skillLvlCfg.Materiars != null && skillLvlCfg.Materiars.Count > 0)
             {
-                sum += skillLvlCfg.Materiars[0][1];
+                sum += skillLvlCfg.Materiars[0].Count;
                 skillLvIndex += 1;
                 skillLvlCfg = CommonDataManager.Tables.TblPassivitySkillLvlCfg.Get(skillLvIndex, skillId);
             }
+
             return sum;
         }
 
         public void InitSuitSyntheticMaterias()
         {
             List<SuitCfg> suitCfgs = new List<SuitCfg>();
-            suitCfgs.AddRange(new List<SuitCfg>( CommonDataManager.Tables.TblSuitCfg.GetGroup1BySyntheticType(1)));
+            suitCfgs.AddRange(new List<SuitCfg>(CommonDataManager.Tables.TblSuitCfg.GetGroup1BySyntheticType(1)));
             suitCfgs.AddRange(new List<SuitCfg>(CommonDataManager.Tables.TblSuitCfg.GetGroup1BySyntheticType(2)));
             suitCfgs.AddRange(new List<SuitCfg>(CommonDataManager.Tables.TblSuitCfg.GetGroup1BySyntheticType(3)));
 
@@ -264,11 +279,14 @@ namespace GFGGame
                         {
                             _suitSyntheticMaterials[materialId] = new List<int>();
                         }
-                        if (_suitSyntheticMaterials[materialId].IndexOf(suitId) < 0) _suitSyntheticMaterials[materialId].Add(suitId);
+
+                        if (_suitSyntheticMaterials[materialId].IndexOf(suitId) < 0)
+                            _suitSyntheticMaterials[materialId].Add(suitId);
                     }
                 }
             }
         }
+
         /// <summary>
         /// 检测物品对应的套装是否全部合成
         /// </summary>
@@ -281,6 +299,7 @@ namespace GFGGame
             {
                 if (!DressUpMenuSuitDataManager.CheckHaveSuit(_suitSyntheticMaterials[itemId][i])) return false;
             }
+
             return true;
         }
     }

+ 2 - 2
GameClient/Assets/Game/HotUpdate/Data/RedDotDataManager.cs

@@ -452,8 +452,8 @@ namespace GFGGame
                 CommonDataManager.Tables.TblPassivitySkillLvlCfg.Get(skillLv + 1, skillId);
             
             if (nextSkillLvlCfg == null || skillLvlCfg.Materiars.Count == 0) return false;
-            long itemHas = ItemDataManager.GetItemNum(skillLvlCfg.Materiars[0][0]);
-            int itemNeed = skillLvlCfg.Materiars[0][1];
+            long itemHas = ItemDataManager.GetItemNum(skillLvlCfg.Materiars[0].ItemId);
+            int itemNeed = skillLvlCfg.Materiars[0].Count;
 
             long costHas = ItemDataManager.GetItemNum(skillLvlCfg.CostID);
             int costNeed = skillLvlCfg.CostNum;

+ 188 - 37
GameClient/Assets/Game/HotUpdate/DressUp/DressUpLayerOperation.cs

@@ -1,4 +1,5 @@
-using ET;
+using System;
+using ET;
 using System.Collections.Generic;
 using cfg.GfgCfg;
 using UnityEngine;
@@ -15,6 +16,7 @@ namespace GFGGame
             Body,
             Head
         }
+
         public const int PRE_RENDER_FRAME = 1;
 
         internal ItemCfg itemCfg;
@@ -31,7 +33,8 @@ namespace GFGGame
 
         private string[] locationsLoading;
 
-        public DressUpLayerOperation(GameObject parentObj, bool needSetMask, bool showAni, string resPath, string effectResPath)
+        public DressUpLayerOperation(GameObject parentObj, bool needSetMask, bool showAni, string resPath,
+            string effectResPath)
         {
             this.parentObj = parentObj;
             this.needSetMask = needSetMask;
@@ -60,39 +63,42 @@ namespace GFGGame
             //LogUtil.LogEditor("update InitHead");
             actionType = EAction.Head;
         }
+
         internal override bool CheckRepeated(DressUpOperationBase t)
         {
             DressUpLayerOperation layerOperation = t as DressUpLayerOperation;
             if (layerOperation != null && layerOperation.actionType == this.actionType)
             {
-                if(actionType == EAction.Layer)
+                if (actionType == EAction.Layer)
                 {
                     return (layerOperation.parentObj == this.parentObj
-                        && layerOperation.itemCfg == this.itemCfg
-                        && layerOperation.layerId == this.layerId);
-
+                            && layerOperation.itemCfg == this.itemCfg
+                            && layerOperation.layerId == this.layerId);
                 }
                 else
                 {
                     return true;
                 }
             }
-            if(this.actionType == EAction.Layer)
+
+            if (this.actionType == EAction.Layer)
             {
                 DressUpRemoveOperation removeOperation = t as DressUpRemoveOperation;
-                if(removeOperation != null && this.itemCfg != null)
+                if (removeOperation != null && this.itemCfg != null)
                 {
-                    if(removeOperation.itemID == this.itemCfg.Id)
+                    if (removeOperation.itemID == this.itemCfg.Id)
                     {
-                        if(removeOperation.parentObj == this.parentObj)
+                        if (removeOperation.parentObj == this.parentObj)
                         {
                             return true;
                         }
                     }
                 }
             }
+
             return false;
         }
+
         /// <summary>
         /// 取消下载
         /// </summary>
@@ -104,13 +110,16 @@ namespace GFGGame
                 {
                     downloaderOperation.CancelDownload();
                 }
-                if(_steps == EDressUpSteps.PreDrawing)
+
+                if (_steps == EDressUpSteps.PreDrawing)
                 {
                     //取消预渲染
                     PrefabManager.Instance.CancelPreDraw(resPath);
                 }
+
                 _steps = EDressUpSteps.Done;
             }
+
             Status = EOperationStatus.Failed;
             Error = "User cancel.";
         }
@@ -122,6 +131,7 @@ namespace GFGGame
                 this.Release();
                 return;
             }
+
             ViewManager.Hide<ModalStatusView>();
 
             switch (actionType)
@@ -162,10 +172,11 @@ namespace GFGGame
             {
                 CheckLoadRes();
             }
-            if(_steps == EDressUpSteps.Loading)
+
+            if (_steps == EDressUpSteps.Loading)
             {
                 Progress = downloaderOperation.Progress;
-                if(downloaderOperation.IsDone)
+                if (downloaderOperation.IsDone)
                 {
                     if (downloaderOperation.Status == EOperationStatus.Succeed)
                     {
@@ -173,6 +184,7 @@ namespace GFGGame
                         {
                             LoadManager.Instance.SetResDownloaded(t);
                         }
+
                         CheckPreDraw();
                     }
                     else
@@ -182,7 +194,8 @@ namespace GFGGame
                     }
                 }
             }
-            if(_steps == EDressUpSteps.PreDrawing)
+
+            if (_steps == EDressUpSteps.PreDrawing)
             {
                 //LogUtil.LogEditor($"preRendering {preRendering}    {resPath} {TimeHelper.ClientNow()}");
                 if (preRendering <= 0)
@@ -190,6 +203,7 @@ namespace GFGGame
                     _steps = EDressUpSteps.Done;
                     Status = EOperationStatus.Succeed;
                 }
+
                 preRendering--;
             }
         }
@@ -197,30 +211,34 @@ namespace GFGGame
         private void CheckLoadRes()
         {
             List<string> locations = new List<string>();
-            if(!string.IsNullOrEmpty(resPath) && !LoadManager.Instance.CheckResExsited(resPath))
+            if (!string.IsNullOrEmpty(resPath) && !LoadManager.Instance.CheckResExsited(resPath))
             {
                 //需加载
                 locations.Add(this.resPath);
             }
-            if(!string.IsNullOrEmpty(effectResPath) && !LoadManager.Instance.CheckResExsited(effectResPath))
+
+            if (!string.IsNullOrEmpty(effectResPath) && !LoadManager.Instance.CheckResExsited(effectResPath))
             {
                 //需加载
                 locations.Add(effectResPath);
             }
-            if(locations.Count == 0)
+
+            if (locations.Count == 0)
             {
                 //文件已在本地,不需要下载
                 CheckPreDraw();
                 return;
             }
+
             locationsLoading = locations.ToArray();
             downloaderOperation = YooAssets.CreateBundleDownloader(locationsLoading, 3, 3);
-            if(downloaderOperation.TotalDownloadCount == 0)
+            if (downloaderOperation.TotalDownloadCount == 0)
             {
                 //文件已在本地,不需要下载
                 CheckPreDraw();
                 return;
             }
+
             ViewManager.Show<ModalStatusView>("资源加载中,请耐心等待...");
             //下载
             _steps = EDressUpSteps.Loading;
@@ -229,7 +247,7 @@ namespace GFGGame
 
         private void CheckPreDraw()
         {
-            if(!string.IsNullOrEmpty(resPath))
+            if (!string.IsNullOrEmpty(resPath))
             {
                 if (showAni)
                 {
@@ -242,96 +260,229 @@ namespace GFGGame
                     return;
                 }
             }
+
             _steps = EDressUpSteps.Done;
             Status = EOperationStatus.Succeed;
         }
 
 
-        private void UpdateLayer()
+        private void UpdateLayer(Action onComplete = null)
         {
             //LogUtil.LogEditor($"add UpdateLayer {itemCfg.id} layerId {layerId}");
             int sortingOrder = ItemTypeCfgArray.Instance.GetSortingOrder(itemCfg.SubType, layerId);
-            //清理旧的
+
+            // 清理旧的
             var spritObjName = DressUpUtil.GetSpriteName(itemCfg, layerId);
             DressUpUtil.TryRemoveSprite(parentObj, spritObjName);
             var aniObjName = string.Format(DressUpUtil.FORMAT_ANIMATION_NAME, itemCfg.Id, layerId);
             DressUpUtil.TryRemoveObj(parentObj, aniObjName);
             string effectObjName = string.Format(DressUpUtil.FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, layerId);
             DressUpUtil.TryRemoveObj(parentObj, effectObjName);
-            //添加新的
-            if(!string.IsNullOrEmpty(this.resPath))
+
+            // 异步操作计数器
+            int asyncOperationCount = 0;
+            bool mainResAdded = false;
+            bool effectResAdded = false;
+
+            // 检查并处理主资源
+            if (!string.IsNullOrEmpty(this.resPath))
             {
+                asyncOperationCount++;
+
                 if (this.showAni)
                 {
-                    DressUpUtil.AddAnimationObj(resPath, aniObjName, parentObj, sortingOrder);
+                    // 异步加载动画
+                    DressUpUtil.AddAnimationObjAsync(
+                        resPath,
+                        aniObjName,
+                        parentObj,
+                        sortingOrder,
+                        (gameObj) =>
+                        {
+                            mainResAdded = gameObj != null;
+                            asyncOperationCount--;
+                            CheckComplete();
+                        });
                 }
                 else
                 {
+                    // 精灵资源异步加载
                     string ext = ItemUtil.GetItemResExt(itemCfg.ItemType, itemCfg.SubType);
-                    DressUpUtil.AddSpriteObj(resPath, spritObjName, parentObj, sortingOrder, needSetMask);
+                    DressUpUtil.AddSpriteObjAsync(
+                        resPath,
+                        spritObjName,
+                        parentObj,
+                        sortingOrder,
+                        needSetMask,
+                        (gameObj) =>
+                        {
+                            if (gameObj != null)
+                            {
+                                mainResAdded = true;
+                            }
+
+                            asyncOperationCount--;
+                            CheckComplete();
+                        });
                 }
             }
+
+            // 检查并处理特效资源(改为同步方式)
             if (!string.IsNullOrEmpty(effectResPath))
             {
-                DressUpUtil.TryAddEffectObj(effectResPath, effectObjName, parentObj, sortingOrder);
+                var effectObj = DressUpUtil.TryAddEffectObj(effectResPath, effectObjName, parentObj, sortingOrder);
+                effectResAdded = effectObj != null;
+            }
+
+            // 如果没有异步操作,直接调用完成回调
+            if (asyncOperationCount == 0)
+            {
+                onComplete?.Invoke();
+            }
+
+            // 检查所有异步操作是否完成
+            void CheckComplete()
+            {
+                if (asyncOperationCount <= 0)
+                {
+                    onComplete?.Invoke();
+                }
             }
         }
 
-        private void UpdateBody()
+        private void UpdateBody(Action onComplete = null)
         {
             //LogUtil.LogEditor("update UpdateBody");
             var spritObjName = DressUpUtil.BODY_SPRITE_NAME;
             var aniObjName = DressUpUtil.BODY_ANIMATION_NAME;
             var effectObjName = DressUpUtil.BODY_EFFECT_OBJ_NAME;
             int sortingOrder = 0;
+
+            // 清理旧的资源(保持同步)
             var removeBodyAni = DressUpUtil.TryRemoveObj(parentObj, aniObjName);
             DressUpUtil.TryRemoveObj(parentObj, effectObjName);
             DressUpUtil.TryRemoveSprite(parentObj, spritObjName);
-            if(!string.IsNullOrEmpty(this.resPath))
+
+            // 异步操作计数器
+            int asyncOperationCount = 0;
+            bool mainResAdded = false;
+            bool effectResAdded = false;
+
+            // 处理主资源
+            if (!string.IsNullOrEmpty(this.resPath))
             {
                 if (this.showAni)
                 {
-                    DressUpUtil.AddAnimationObj(this.resPath, aniObjName, parentObj, sortingOrder);
+                    // 异步加载动画
+                    DressUpUtil.AddAnimationObjAsync(
+                        resPath,
+                        aniObjName,
+                        parentObj,
+                        sortingOrder,
+                        (gameObj) => { mainResAdded = true; });
                 }
                 else
                 {
-                    DressUpUtil.AddSpriteObj(this.resPath, spritObjName, parentObj, sortingOrder, needSetMask);
+                    // 精灵资源改为异步加载
+                    asyncOperationCount++;
+                    DressUpUtil.AddSpriteObjAsync(
+                        this.resPath,
+                        spritObjName,
+                        parentObj,
+                        sortingOrder,
+                        needSetMask,
+                        (gameObj) =>
+                        {
+                            if (gameObj != null)
+                            {
+                                mainResAdded = true;
+                            }
+
+                            // 如果从动画切换到精灵且移除了动画,重置位置和旋转
+                            if (!this.showAni && removeBodyAni)
+                            {
+                                parentObj.transform.localPosition = Vector3.zero;
+                                parentObj.transform.localRotation = Quaternion.identity;
+                            }
+
+                            asyncOperationCount--;
+                            CheckComplete();
+                        });
                 }
             }
-            if(!this.showAni && removeBodyAni)
+
+            // 处理特效资源(假设TryAddEffectObj保持同步)
+            if (!string.IsNullOrEmpty(effectResPath))
+            {
+                DressUpUtil.TryAddEffectObj(effectResPath, effectObjName, parentObj, sortingOrder);
+                effectResAdded = true;
+            }
+
+            // 如果没有异步操作且需要执行位置重置(动画切换情况)
+            if (asyncOperationCount == 0 && !this.showAni && removeBodyAni)
             {
                 parentObj.transform.localPosition = Vector3.zero;
                 parentObj.transform.localRotation = Quaternion.identity;
             }
-            if (!string.IsNullOrEmpty(effectResPath))
+
+            // 检查所有异步操作是否完成
+            void CheckComplete()
             {
-                DressUpUtil.TryAddEffectObj(effectResPath, effectObjName, parentObj, sortingOrder);
+                if (asyncOperationCount <= 0)
+                {
+                    onComplete?.Invoke();
+                }
+            }
+
+            // 如果没有异步操作,直接调用完成回调
+            if (asyncOperationCount == 0)
+            {
+                onComplete?.Invoke();
             }
         }
 
-        private void UpdateHead()
+        private void UpdateHead(Action onComplete = null)
         {
             LogUtil.LogEditor("update UpdateHead");
-            var spritObjName = DressUpUtil.HEAD_SPRITE_NAME; 
+            var spritObjName = DressUpUtil.HEAD_SPRITE_NAME;
             int sortingOrder = 1;
             Transform transform_t = parentObj.transform.Find(spritObjName);
+
             if (!string.IsNullOrEmpty(this.resPath))
             {
                 if (transform_t != null)
                 {
+                    // 如果对象已存在,直接激活并返回
                     transform_t.gameObject.SetActive(true);
+                    onComplete?.Invoke();
                     return;
                 }
-                DressUpUtil.AddSpriteObj(resPath, spritObjName, parentObj, sortingOrder, needSetMask);
+
+                // 异步添加精灵对象
+                DressUpUtil.AddSpriteObjAsync(
+                    resPath,
+                    spritObjName,
+                    parentObj,
+                    sortingOrder,
+                    needSetMask,
+                    (gameObj) =>
+                    {
+                        // 回调中可以添加额外处理逻辑(如有需要)
+                        onComplete?.Invoke();
+                    });
             }
             else
             {
+                // 资源路径为空时,隐藏现有对象
                 if (transform_t == null)
                 {
+                    onComplete?.Invoke();
                     return;
                 }
+
                 transform_t.gameObject.SetActive(false);
+                onComplete?.Invoke();
             }
         }
     }
-}
+}

+ 261 - 100
GameClient/Assets/Game/HotUpdate/DressUp/DressUpUtil.cs

@@ -23,14 +23,16 @@ namespace GFGGame
         public const string FORMAT_ANIMATION_NAME = "I_{0}_a{1}";
         public const string FORMAT_EFFECT_OBJ_NAME = "I_{0}_e{1}";
 
-        public static List<DressUpLayerOperation> AddItemAsync(int itemID, GameObject sceneObj, bool needSetMask = false, bool showAni = true, GameObject parentObj = null, int resLayer = 0)
+        public static List<DressUpLayerOperation> AddItemAsync(int itemID, GameObject sceneObj,
+            bool needSetMask = false, bool showAni = true, GameObject parentObj = null, int resLayer = 0)
         {
             ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID);
             if (itemCfg == null) return null;
 
             if (parentObj == null)
             {
-                if (itemCfg.SubType == ConstDressUpItemType.BEI_JING || DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType))
+                if (itemCfg.SubType == ConstDressUpItemType.BEI_JING ||
+                    DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType))
                 {
                     parentObj = sceneObj;
                 }
@@ -41,6 +43,7 @@ namespace GFGGame
                     parentObj = role.gameObject;
                 }
             }
+
             showAni = showAni || itemCfg.SubType == ConstDressUpItemType.ZHUANG_RONG;
             List<DressUpLayerOperation> handlers = new List<DressUpLayerOperation>();
             DressUpLayerOperation handler;
@@ -59,6 +62,7 @@ namespace GFGGame
                         layerName = itemCfg.ResLayer3;
                         break;
                 }
+
                 if (!string.IsNullOrEmpty(layerName))
                 {
                     handler = UpdateLayerResAsync(itemCfg, parentObj, resLayer, needSetMask, showAni);
@@ -73,41 +77,44 @@ namespace GFGGame
                     handler = UpdateLayerResAsync(itemCfg, parentObj, 1, needSetMask, showAni);
                     if (handler != null) handlers.Add(handler);
                 }
+
                 //第二层
                 if (!string.IsNullOrEmpty(itemCfg.ResLayer2))
                 {
-
                     handler = UpdateLayerResAsync(itemCfg, parentObj, 2, needSetMask, showAni);
                     if (handler != null) handlers.Add(handler);
                 }
+
                 //第三层
                 if (!string.IsNullOrEmpty(itemCfg.ResLayer3))
                 {
-
                     handler = UpdateLayerResAsync(itemCfg, parentObj, 3, needSetMask, showAni);
                     if (handler != null) handlers.Add(handler);
                 }
             }
-            if(handlers.Count > 0)
+
+            if (handlers.Count > 0)
             {
                 return handlers;
             }
+
             return null;
         }
 
         public static string GetSpriteName(ItemCfg itemCfg, int layer)
         {
-            if(itemCfg.SubType == ConstDressUpItemType.BEI_JING)
+            if (itemCfg.SubType == ConstDressUpItemType.BEI_JING)
             {
                 return "Bg";
             }
+
             return string.Format(FORMAT_SPRITE_NAME, itemCfg.Id, layer);
         }
 
         public static void RemoveItem(int itemID, GameObject parentObj)
         {
             ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID);
-            if (itemCfg == null || parentObj== null) return;
+            if (itemCfg == null || parentObj == null) return;
             string spritObjName;
             string aniObjName;
             //默认层
@@ -120,6 +127,7 @@ namespace GFGGame
                 aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 1);
                 TryRemoveObj(parentObj, aniObjName);
             }
+
             //特殊层
             if (!string.IsNullOrEmpty(itemCfg.ResLayer2))
             {
@@ -130,6 +138,7 @@ namespace GFGGame
                 aniObjName = string.Format(FORMAT_EFFECT_OBJ_NAME, itemCfg.Id, 2);
                 TryRemoveObj(parentObj, aniObjName);
             }
+
             //第三层
             if (!string.IsNullOrEmpty(itemCfg.ResLayer3))
             {
@@ -142,13 +151,15 @@ namespace GFGGame
             }
         }
 
-        public static DressUpRemoveOperation RemoveItemAsync(int itemID, GameObject sceneObj, GameObject parentObj = null)
+        public static DressUpRemoveOperation RemoveItemAsync(int itemID, GameObject sceneObj,
+            GameObject parentObj = null)
         {
             ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemID);
             if (itemCfg == null) return null;
             if (parentObj == null)
             {
-                if (itemCfg.SubType == ConstDressUpItemType.BEI_JING || DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType))
+                if (itemCfg.SubType == ConstDressUpItemType.BEI_JING ||
+                    DressUpMenuItemCfg1Array.Instance.CheckIsSceneTypeBySubType(itemCfg.SubType))
                 {
                     parentObj = sceneObj;
                 }
@@ -159,29 +170,33 @@ namespace GFGGame
                     parentObj = role.gameObject;
                 }
             }
+
             var operation = new DressUpRemoveOperation(itemID, parentObj);
             operation.Begin();
             return operation;
         }
 
-        public static DressUpLayerOperation UpdateHeadAsync(bool show, GameObject sceneObj, bool needSetMask = false, GameObject parentObj = null)
+        public static DressUpLayerOperation UpdateHeadAsync(bool show, GameObject sceneObj, bool needSetMask = false,
+            GameObject parentObj = null)
         {
             var roleTf = sceneObj.transform.Find(ROLE_OBJ_NAME);
             parentObj = parentObj == null ? roleTf.gameObject : parentObj;
             string res = null;
             string resPath = null;
-            if(show)
+            if (show)
             {
                 res = HEAD_DEFAULT_RES_NAME;
                 resPath = ResPathUtil.GetDressUpPath(res);
             }
+
             DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, false, resPath, null);
             handler.InitHead();
             handler.Begin();
             return handler;
         }
 
-        public static DressUpLayerOperation UpdateBodyAsync(string actionRes, GameObject sceneObj, bool needSetMask = false, GameObject parentObj = null, int itemIdLianYiQun = 0)
+        public static DressUpLayerOperation UpdateBodyAsync(string actionRes, GameObject sceneObj,
+            bool needSetMask = false, GameObject parentObj = null, int itemIdLianYiQun = 0)
         {
             //角色
             var roleTf = sceneObj.transform.Find(ROLE_OBJ_NAME);
@@ -195,12 +210,13 @@ namespace GFGGame
             if (showAni)
             {
                 aniResPath = ResPathUtil.GetDressUpAnimationPath(actionRes);
-                if(!YooAssets.CheckResExist(aniResPath))
+                if (!YooAssets.CheckResExist(aniResPath))
                 {
                     showAni = false;
                 }
             }
-            if(showAni)
+
+            if (showAni)
             {
                 resPath = aniResPath;
                 //特效
@@ -213,12 +229,13 @@ namespace GFGGame
             else
             {
                 bool hideBody = false;
-                if(itemIdLianYiQun > 0)
+                if (itemIdLianYiQun > 0)
                 {
                     ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(itemIdLianYiQun);
                     hideBody = itemCfg.HideBody > 0;
                 }
-                if(hideBody)
+
+                if (hideBody)
                 {
                     resPath = null;
                 }
@@ -226,15 +243,17 @@ namespace GFGGame
                 {
                     resPath = ResPathUtil.GetDressUpPath(BODY_DEFAULT_RES_NAME, extPng);
                 }
-
             }
-            DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath);
+
+            DressUpLayerOperation handler =
+                new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath);
             handler.InitBody();
             handler.Begin();
             return handler;
         }
 
-        private static DressUpLayerOperation UpdateLayerResAsync(ItemCfg itemCfg, GameObject parentObj, int layerId, bool needSetMask, bool showAni = true)
+        private static DressUpLayerOperation UpdateLayerResAsync(ItemCfg itemCfg, GameObject parentObj, int layerId,
+            bool needSetMask, bool showAni = true)
         {
             string resPath;
             string aniResPath = null;
@@ -242,7 +261,7 @@ namespace GFGGame
             if (showAni)
             {
                 aniResPath = ResPathUtil.GetDressUpLayerAnimationResPath(itemCfg, layerId);
-                if(!YooAssets.CheckResExist(aniResPath))
+                if (!YooAssets.CheckResExist(aniResPath))
                 {
                     showAni = false;
                 }
@@ -268,111 +287,202 @@ namespace GFGGame
             {
                 effectResPath = null;
             }
-            DressUpLayerOperation handler = new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath);
+
+            DressUpLayerOperation handler =
+                new DressUpLayerOperation(parentObj, needSetMask, showAni, resPath, effectResPath);
             handler.InitLayer(itemCfg, layerId);
             handler.Begin();
             return handler;
         }
 
-        public static GameObject AddSpriteObj(string resPath, string objName, GameObject parentObj, int sortingOrder, bool needSetMask)
+        public static void AddSpriteObjAsync(
+            string resPath,
+            string objName,
+            GameObject parentObj,
+            int sortingOrder,
+            bool needSetMask,
+            Action<GameObject> onComplete)
         {
+            // 检查资源是否存在
             if (!YooAssets.CheckResExist(resPath))
             {
-                return null;
+                onComplete?.Invoke(null);
+                return;
             }
-            var gameObj = GetGameObjExisted(parentObj, objName, resPath);
-            if (gameObj != null)
+
+            // 检查是否已存在相同对象
+            var existedObj = GetGameObjExisted(parentObj, objName, resPath);
+            if (existedObj != null)
             {
-                return gameObj;
+                onComplete?.Invoke(existedObj);
+                return;
             }
-            SpriteRenderer spr = null;
-            gameObj = parentObj.transform.Find(objName)?.gameObject;
+
+            // 查找或创建游戏对象
+            GameObject gameObj = parentObj.transform.Find(objName)?.gameObject;
             if (gameObj == null)
             {
                 gameObj = new GameObject(objName);
                 gameObj.transform.SetParent(parentObj.transform, false);
             }
-            spr = gameObj.GetComponent<SpriteRenderer>();
+
+            // 获取或添加SpriteRenderer
+            SpriteRenderer spr = gameObj.GetComponent<SpriteRenderer>();
             if (spr == null)
             {
                 spr = gameObj.AddComponent<SpriteRenderer>();
             }
-            float tx, ty;
-            LoadSpritePos(resPath, out tx, out ty);
-            gameObj.transform.localPosition = new Vector3(tx, ty, gameObj.transform.localPosition.z);
-            SpriteHelper.AddSpriteTo(spr, resPath);
-            gameObj.SetActive(true);
-            spr.sortingOrder = sortingOrder;
 
-            if (needSetMask)
+            // 异步加载精灵位置
+            LoadSpritePosAsync(resPath, (tx, ty) =>
             {
-                spr.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
-                if (parentObj.transform.parent != null && parentObj.transform.parent.name == "targetRole")
+                // 设置位置
+                gameObj.transform.localPosition = new Vector3(tx, ty, gameObj.transform.localPosition.z);
+
+                // 添加精灵
+                SpriteHelper.AddSpriteTo(spr, resPath);
+                gameObj.SetActive(true);
+                spr.sortingOrder = sortingOrder;
+
+                // 设置遮罩交互
+                if (needSetMask)
                 {
-                    spr.maskInteraction = SpriteMaskInteraction.VisibleOutsideMask;
+                    spr.maskInteraction = parentObj.transform.parent != null &&
+                                          parentObj.transform.parent.name == "targetRole"
+                        ? SpriteMaskInteraction.VisibleOutsideMask
+                        : SpriteMaskInteraction.VisibleInsideMask;
                 }
                 else
                 {
-                    spr.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
+                    spr.maskInteraction = SpriteMaskInteraction.None;
                 }
-            }
-            else
-            {
-                spr.maskInteraction = SpriteMaskInteraction.None;
-            }
-            return gameObj;
+
+                onComplete?.Invoke(gameObj);
+            });
         }
 
-        public static GameObject AddAnimationObj(string resPath, string objName, GameObject parentObj, int sortingOrder)
+        public static void AddAnimationObjAsync(
+            string resPath,
+            string objName,
+            GameObject parentObj,
+            int sortingOrder,
+            Action<GameObject> callback)
         {
+            // 检查已有对象
             var gameObj = GetGameObjExisted(parentObj, objName, resPath);
             if (gameObj != null)
             {
-                return gameObj;
+                callback?.Invoke(gameObj);
+                return;
             }
-            gameObj = PrefabManager.Instance.SpawnSync(resPath);
-            if (gameObj == null)
-            {
-                return null;
-            }
-            if (objName == BODY_ANIMATION_NAME)
+
+            // 异步加载预制体
+            PrefabManager.Instance.SpawnAsync(resPath, (loadedObj) =>
             {
-                //这里有个需求是一些特殊动作需要自定义位置和角度,
-                //实现方法就是美术在动作预制体上设置这个位置,
-                //然后程序记录下这个位置,把他设置到role节点上,并把动作节点的位置重置成默认值。
-                DressUpOffsetInfo dressUpOffsetInfo = gameObj.GetComponent<DressUpOffsetInfo>();
-                if(dressUpOffsetInfo == null)
+                if (loadedObj == null)
                 {
-                    dressUpOffsetInfo = gameObj.AddComponent<DressUpOffsetInfo>();
-                    dressUpOffsetInfo.OffsetPosition = gameObj.transform.localPosition;
-                    dressUpOffsetInfo.Rotation = gameObj.transform.localRotation;
+                    callback?.Invoke(null);
+                    return;
                 }
-                //如果是动作动画,就根据动画位置及角度信息设置给Role对象
-                parentObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition;
-                parentObj.transform.rotation = dressUpOffsetInfo.Rotation;
-                //.SetPositionAndRotation(Vector3.zero, Quaternion.identity); 
-            }
-            gameObj.transform.localPosition = Vector3.zero;
-            gameObj.transform.rotation = Quaternion.identity;
-            gameObj.name = objName;
-            gameObj.transform.SetParent(parentObj.transform, false);
-            var render = gameObj.GetComponent<CubismRenderController>();
-            if (render == null && gameObj.transform.childCount > 0)
-            {
-                var childObj = gameObj.transform.GetChild(0);
-                if (childObj != null)
+
+                if (objName == BODY_ANIMATION_NAME)
                 {
-                    render = childObj.GetComponent<CubismRenderController>();
+                    DressUpOffsetInfo dressUpOffsetInfo = loadedObj.GetComponent<DressUpOffsetInfo>();
+                    if (dressUpOffsetInfo == null)
+                    {
+                        dressUpOffsetInfo = loadedObj.AddComponent<DressUpOffsetInfo>();
+                        dressUpOffsetInfo.OffsetPosition = loadedObj.transform.localPosition;
+                        dressUpOffsetInfo.Rotation = loadedObj.transform.localRotation;
+                    }
+
+                    parentObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition;
+                    parentObj.transform.rotation = dressUpOffsetInfo.Rotation;
                 }
-            }
-            if (render != null && render.gameObject.activeSelf == true)
-            {
-                render.SortingOrder = sortingOrder;
-            }
-            SetRenderersOrder(gameObj, sortingOrder);
-            return gameObj;
+
+                // 设置位置和父对象
+                loadedObj.transform.localPosition = Vector3.zero;
+                loadedObj.transform.rotation = Quaternion.identity;
+                loadedObj.name = objName;
+                loadedObj.transform.SetParent(parentObj.transform, false);
+
+                // 设置渲染顺序
+                var render = loadedObj.GetComponent<CubismRenderController>();
+                if (render == null && loadedObj.transform.childCount > 0)
+                {
+                    var childObj = loadedObj.transform.GetChild(0);
+                    if (childObj != null)
+                    {
+                        render = childObj.GetComponent<CubismRenderController>();
+                    }
+                }
+
+                if (render != null && render.gameObject.activeSelf)
+                {
+                    render.SortingOrder = sortingOrder;
+                }
+
+                SetRenderersOrder(loadedObj, sortingOrder);
+
+                callback?.Invoke(loadedObj);
+            });
         }
 
+        // public static GameObject AddAnimationObj(string resPath, string objName, GameObject parentObj, int sortingOrder)
+        // {
+        //     var gameObj = GetGameObjExisted(parentObj, objName, resPath);
+        //     if (gameObj != null)
+        //     {
+        //         return gameObj;
+        //     }
+        //
+        //     gameObj = PrefabManager.Instance.SpawnSync(resPath);
+        //     if (gameObj == null)
+        //     {
+        //         return null;
+        //     }
+        //
+        //     if (objName == BODY_ANIMATION_NAME)
+        //     {
+        //         //这里有个需求是一些特殊动作需要自定义位置和角度,
+        //         //实现方法就是美术在动作预制体上设置这个位置,
+        //         //然后程序记录下这个位置,把他设置到role节点上,并把动作节点的位置重置成默认值。
+        //         DressUpOffsetInfo dressUpOffsetInfo = gameObj.GetComponent<DressUpOffsetInfo>();
+        //         if (dressUpOffsetInfo == null)
+        //         {
+        //             dressUpOffsetInfo = gameObj.AddComponent<DressUpOffsetInfo>();
+        //             dressUpOffsetInfo.OffsetPosition = gameObj.transform.localPosition;
+        //             dressUpOffsetInfo.Rotation = gameObj.transform.localRotation;
+        //         }
+        //
+        //         //如果是动作动画,就根据动画位置及角度信息设置给Role对象
+        //         parentObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition;
+        //         parentObj.transform.rotation = dressUpOffsetInfo.Rotation;
+        //         //.SetPositionAndRotation(Vector3.zero, Quaternion.identity); 
+        //     }
+        //
+        //     gameObj.transform.localPosition = Vector3.zero;
+        //     gameObj.transform.rotation = Quaternion.identity;
+        //     gameObj.name = objName;
+        //     gameObj.transform.SetParent(parentObj.transform, false);
+        //     var render = gameObj.GetComponent<CubismRenderController>();
+        //     if (render == null && gameObj.transform.childCount > 0)
+        //     {
+        //         var childObj = gameObj.transform.GetChild(0);
+        //         if (childObj != null)
+        //         {
+        //             render = childObj.GetComponent<CubismRenderController>();
+        //         }
+        //     }
+        //
+        //     if (render != null && render.gameObject.activeSelf == true)
+        //     {
+        //         render.SortingOrder = sortingOrder;
+        //     }
+        //
+        //     SetRenderersOrder(gameObj, sortingOrder);
+        //     return gameObj;
+        // }
+
         public static GameObject TryAddEffectObj(string resPath, string objName, GameObject parentObj, int sortingOrder)
         {
             var gameObj = GetGameObjExisted(parentObj, objName, resPath);
@@ -380,6 +490,7 @@ namespace GFGGame
             {
                 return gameObj;
             }
+
             gameObj = PrefabManager.Instance.SpawnSync(resPath);
             if (gameObj == null)
             {
@@ -394,6 +505,7 @@ namespace GFGGame
                 dressUpOffsetInfo.OffsetPosition = gameObj.transform.localPosition;
                 dressUpOffsetInfo.Rotation = gameObj.transform.localRotation;
             }
+
             gameObj.transform.localPosition = dressUpOffsetInfo.OffsetPosition;
             gameObj.transform.rotation = dressUpOffsetInfo.Rotation;
             gameObj.transform.SetParent(parentObj.transform, false);
@@ -403,7 +515,8 @@ namespace GFGGame
             {
                 GameObject.Destroy(sortingGroup);
             }
-            SetRenderersOrder(gameObj, sortingOrder + 1);//特效层默认高一个层级
+
+            SetRenderersOrder(gameObj, sortingOrder + 1); //特效层默认高一个层级
             return gameObj;
         }
 
@@ -413,6 +526,7 @@ namespace GFGGame
             {
                 return false;
             }
+
             Transform transform = parentObj.transform.Find(objName);
             if (transform != null)
             {
@@ -423,6 +537,7 @@ namespace GFGGame
                     return true;
                 }
             }
+
             return false;
         }
 
@@ -432,6 +547,7 @@ namespace GFGGame
             {
                 return false;
             }
+
             Transform transform = parentObj.transform.Find(objName);
             if (transform != null)
             {
@@ -439,15 +555,17 @@ namespace GFGGame
                 if (gameObj != null)
                 {
                     var spr = gameObj.GetComponent<SpriteRenderer>();
-                    if(spr != null)
+                    if (spr != null)
                     {
                         //LogUtil.LogEditor($"TryRemoveSprite {objName}");
                         SpriteHelper.RemoveSpriteFrom(spr);
                         gameObj.SetActive(false);
                     }
+
                     return true;
                 }
             }
+
             return false;
         }
 
@@ -457,6 +575,7 @@ namespace GFGGame
             {
                 return null;
             }
+
             Transform transform = parentObj.transform.Find(objName);
             if (transform != null)
             {
@@ -473,27 +592,64 @@ namespace GFGGame
                     }
                 }
             }
+
             return null;
         }
 
-        public static void LoadSpritePos(string resPath, out float tx, out float ty)
+        // public static void LoadSpritePos(string resPath, out float tx, out float ty)
+        // {
+        //     int index = resPath.LastIndexOf('.');
+        //     resPath = resPath.Substring(0, index) + ".bytes";
+        //     if (YooAssets.CheckResExist(resPath))
+        //     {
+        //         var handle = YooAssets.LoadAssetSync<TextAsset>(resPath);
+        //         TextAsset asset = handle.AssetObject as TextAsset;
+        //         var st = new MemoryStream(asset.bytes);
+        //         var br = new BinaryReader(st);
+        //         tx = br.ReadInt32() / 100f;
+        //         ty = -br.ReadInt32() / 100f;
+        //         handle.Release();
+        //     }
+        //     else
+        //     {
+        //         tx = 0;
+        //         ty = 0;
+        //     }
+        // }
+
+        public static void LoadSpritePosAsync(string resPath, Action<float, float> onComplete)
         {
             int index = resPath.LastIndexOf('.');
             resPath = resPath.Substring(0, index) + ".bytes";
+
             if (YooAssets.CheckResExist(resPath))
             {
-                var handle = YooAssets.LoadAssetSync<TextAsset>(resPath);
-                TextAsset asset = handle.AssetObject as TextAsset;
-                var st = new MemoryStream(asset.bytes);
-                var br = new BinaryReader(st);
-                tx = br.ReadInt32() / 100f;
-                ty = -br.ReadInt32() / 100f;
-                handle.Release();
+                var handle = YooAssets.LoadAssetAsync<TextAsset>(resPath);
+                handle.Completed += (operation) =>
+                {
+                    if (operation.Status == EOperationStatus.Succeed)
+                    {
+                        TextAsset asset = operation.AssetObject as TextAsset;
+                        using (var st = new MemoryStream(asset.bytes))
+                        using (var br = new BinaryReader(st))
+                        {
+                            float tx = br.ReadInt32() / 100f;
+                            float ty = -br.ReadInt32() / 100f;
+                            onComplete?.Invoke(tx, ty);
+                        }
+                    }
+                    else
+                    {
+                        Debug.LogError($"Failed to load position data: {resPath}");
+                        onComplete?.Invoke(0, 0);
+                    }
+
+                    operation.Release();
+                };
             }
             else
             {
-                tx = 0;
-                ty = 0;
+                onComplete?.Invoke(0, 0);
             }
         }
 
@@ -508,6 +664,7 @@ namespace GFGGame
                     renderer.sortingOrder = sortingOrder;
                 }
             }
+
             ParticleSystem[] particles = gameObj.transform.GetComponentsInChildren<ParticleSystem>();
             for (int i = 0; i < particles.Length; i++)
             {
@@ -517,21 +674,24 @@ namespace GFGGame
                     renderer.sortingOrder = sortingOrder;
                 }
             }
+
             var spritesRenderers = gameObj.transform.GetComponentsInChildren<SpriteRenderer>();
-            for(int i = 0; i < spritesRenderers.Length; i++)
+            for (int i = 0; i < spritesRenderers.Length; i++)
             {
                 var spriteRender = spritesRenderers[i];
                 spriteRender.sortingOrder = sortingOrder;
             }
         }
 
-        public static List<int> GetSuitItems(int suitId, bool isAction, int[] excludeType = null, bool showOptional = true, bool CheckOwn = true,bool isDress = false)
+        public static List<int> GetSuitItems(int suitId, bool isAction, int[] excludeType = null,
+            bool showOptional = true, bool CheckOwn = true, bool isDress = false)
         {
             SuitCfg suitCfg = CommonDataManager.Tables.TblSuitCfg.GetOrDefault(suitId);
             if (suitCfg == null)
             {
                 return null;
             }
+
             List<int> items = new List<int>(suitCfg.Parts);
             if (showOptional)
             {
@@ -540,6 +700,7 @@ namespace GFGGame
                     items.AddRange(suitCfg.PartsOptional);
                 }
             }
+
             int subType = 0;
             //找到要穿的散件
             List<int> targetItemList = new List<int>();
@@ -558,8 +719,8 @@ namespace GFGGame
                     }
                 }
             }
+
             return targetItemList;
         }
     }
-
-}
+}

+ 25 - 5
GameClient/Assets/Game/HotUpdate/DressUp/SceneController.cs

@@ -1,3 +1,4 @@
+using System;
 using UnityEngine;
 using System.Collections;
 using YooAsset;
@@ -85,22 +86,41 @@ namespace GFGGame
             }
         }
 
-        public static void InitPicFace(string faceValue, GameObject sceneObj)
+        public static void InitPicFaceAsync(string faceValue, GameObject sceneObj, Action onComplete = null)
         {
             Transform face = sceneObj.transform.Find("Pic/Face");
+            if (face == null)
+            {
+                Debug.LogError("Face transform not found!");
+                onComplete?.Invoke();
+                return;
+            }
+
             SpriteRenderer sprFace = face.GetComponent<SpriteRenderer>();
+            if (sprFace == null)
+            {
+                Debug.LogError("SpriteRenderer component not found on Face object!");
+                onComplete?.Invoke();
+                return;
+            }
 
             if (faceValue == "0")
             {
                 SpriteHelper.RemoveSpriteFrom(sprFace);
+                onComplete?.Invoke();
             }
             else
             {
                 var resPath = ResPathUtil.GetNpcPicFacePath(faceValue);
-                float tx, ty;
-                DressUpUtil.LoadSpritePos(resPath, out tx, out ty);
-                face.localPosition = new Vector3(tx, ty, face.localPosition.z);
-                SpriteHelper.AddSpriteTo(sprFace, resPath);
+
+                // 异步加载位置信息
+                DressUpUtil.LoadSpritePosAsync(resPath, (tx, ty) =>
+                {
+                    face.localPosition = new Vector3(tx, ty, face.localPosition.z);
+
+                    // 异步添加精灵
+                    SpriteHelper.AddSpriteToAsync(sprFace, resPath, () => { onComplete?.Invoke(); });
+                });
             }
         }
 

+ 12 - 0
GameClient/Assets/Game/HotUpdate/Utils/SuitUtil.cs

@@ -180,6 +180,18 @@ namespace GFGGame
                 SuitCfg suitCfgA = CommonDataManager.Tables.TblSuitCfg.GetOrDefault(a);
                 SuitCfg suitCfgB = CommonDataManager.Tables.TblSuitCfg.GetOrDefault(b);
 
+                if (suitCfgA == null)
+                {
+                    Debug.LogWarning($"suitCfgA is null. suitCfgId:{a} ");
+                    return 1;
+                }
+
+                if (suitCfgB == null)
+                {
+                    Debug.LogWarning($"suitCfgB is null. suitCfgId:{b}");
+                    return -1;
+                }
+
                 if (suitCfgB.Rarity > suitCfgA.Rarity)
                 {
                     return 1;

+ 5 - 5
GameClient/Assets/Game/HotUpdate/Views/Card/CardSkillView.cs

@@ -116,12 +116,12 @@ namespace GFGGame
             UI_ComStarConsume listItem = UI_ComStarConsume.Proxy(obj);
             // int skillLv = SkillDataManager.Instance.GetSkillLv(_cardId, _skillId);
             // skillCfg = SkillDataManager.Instance.GetPassivitySkillCfg(_cardId, _skillId, skillLv);
-            ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(skillLvCfg.Materiars[index][0]);
+            ItemCfg itemCfg = CommonDataManager.Tables.TblItemCfg.GetOrDefault(skillLvCfg.Materiars[index].ItemId);
 
             listItem.m_loaItem.url = ResPathUtil.GetIconPath(itemCfg);
 
-            int needCount = skillLvCfg.Materiars[index][1];
-            long hasCount = ItemDataManager.GetItemNum(skillLvCfg.Materiars[index][0]);
+            int needCount = skillLvCfg.Materiars[index].Count;
+            long hasCount = ItemDataManager.GetItemNum(skillLvCfg.Materiars[index].Count);
             listItem.m_txtNeedCount.text = needCount.ToString();
             listItem.m_txtHasCount.text =
                 StringUtil.GetColorText(hasCount.ToString(), hasCount < needCount ? "#D27869" : "#716660");
@@ -132,7 +132,7 @@ namespace GFGGame
                 listItem.target.onClick.Add(() => OnClickBtnPlusStarConsum(index));
             }
 
-            listItem.target.data = skillLvCfg.Materiars[index][0];
+            listItem.target.data = skillLvCfg.Materiars[index].ItemId;
 
             if (hasCount < needCount)
             {
@@ -165,7 +165,7 @@ namespace GFGGame
 
             for (int i = 0; i < skillLvCfg.Materiars.Count; i++)
             {
-                if (!ItemUtil.CheckItemEnough(skillLvCfg.Materiars[i][0], skillLvCfg.Materiars[i][1], true))
+                if (!ItemUtil.CheckItemEnough(skillLvCfg.Materiars[i].Count, skillLvCfg.Materiars[i].ItemId, true))
                     return;
             }
 

+ 5 - 0
GameClient/Assets/Game/HotUpdate/Views/DressUp/DressUpView.cs

@@ -815,6 +815,10 @@ namespace GFGGame
             if (_currentMenuType == (int)ConstDressUpItemType.TAO_ZHUANG)
             {
                 SuitCfg suitCfg = CommonDataManager.Tables.TblSuitCfg.GetOrDefault(id);
+                if (suitCfg == null)
+                {
+                    return;
+                }
                 iconRes = suitCfg.Res;
                 partName = suitCfg.Name;
                 listItem.m_iconSelected.visible = false;
@@ -976,6 +980,7 @@ namespace GFGGame
 
             for (int i = 0; i < count; i++)
             {
+                Debug.Log(i);
                 UI_PartsListItem listItem = UI_PartsListItem.Proxy(list.GetChildAt(i));
                 int id = (int)listItem.target.data;
                 if (_currentMenuType == ConstDressUpItemType.TAO_ZHUANG)

+ 12 - 7
GameClient/Assets/Game/HotUpdate/Views/MainStory/StoryDialogView.cs

@@ -884,22 +884,27 @@ namespace GFGGame
 
         private void UpdatePic(string value, string faceValue = "", string emojiValue = "")
         {
-            if (IsTeaParty)
-            {
-                return;
-            }
+            if (IsTeaParty) return;
 
+            // 同步处理 value
             if (value.Length > 0)
             {
                 SceneController.UpdateDialogPic(value, _sceneObject);
             }
 
+            // 异步处理 faceValue
             if (faceValue.Length > 0)
             {
-                SceneController.InitPicFace(faceValue, _sceneObject);
+                SceneController.InitPicFaceAsync(faceValue, _sceneObject, () =>
+                {
+                    // faceValue 加载完成后处理 emojiValue
+                    if (emojiValue.Length > 0)
+                    {
+                        UpdateLiveEmoji(emojiValue);
+                    }
+                });
             }
-
-            if (emojiValue.Length > 0)
+            else if (emojiValue.Length > 0) // 如果不需要加载 faceValue,直接处理 emoji
             {
                 UpdateLiveEmoji(emojiValue);
             }

+ 508 - 476
GameClient/Assets/YooAsset/Runtime/YooAssetsExtension.cs

@@ -6,480 +6,512 @@ using UnityEngine.SceneManagement;
 
 namespace YooAsset
 {
-	public static partial class YooAssets
-	{
-		private static ResourcePackage _defaultPackage;
-
-		/// <summary>
-		/// 设置默认的资源包
-		/// </summary>
-		public static void SetDefaultPackage(ResourcePackage package)
-		{
-			_defaultPackage = package;
-		}
-
-		#region 资源信息
-		/// <summary>
-		/// 是否需要从远端更新下载
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		public static bool IsNeedDownloadFromRemote(string location)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.IsNeedDownloadFromRemote(location);
-		}
-
-		/// <summary>
-		/// 是否需要从远端更新下载
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		public static bool IsNeedDownloadFromRemote(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.IsNeedDownloadFromRemote(assetInfo);
-		}
-
-		/// <summary>
-		/// 获取资源信息列表
-		/// </summary>
-		/// <param name="tag">资源标签</param>
-		public static AssetInfo[] GetAssetInfos(string tag)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.GetAssetInfos(tag);
-		}
-
-		/// <summary>
-		/// 获取资源信息列表
-		/// </summary>
-		/// <param name="tags">资源标签列表</param>
-		public static AssetInfo[] GetAssetInfos(string[] tags)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.GetAssetInfos(tags);
-		}
-
-		/// <summary>
-		/// 获取资源信息
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		public static AssetInfo GetAssetInfo(string location)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.GetAssetInfo(location);
-		}
-
-		/// <summary>
-		/// 检查资源定位地址是否有效
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		public static bool CheckLocationValid(string location)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CheckLocationValid(location);
-		}
-		#endregion
-
-		#region 原生文件
-		/// <summary>
-		/// 同步加载原生文件
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static RawFileOperationHandle LoadRawFileSync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadRawFileSync(assetInfo);
-		}
-
-		/// <summary>
-		/// 同步加载原生文件
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		public static RawFileOperationHandle LoadRawFileSync(string location)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadRawFileSync(location);
-		}
-
-		/// <summary>
-		/// 异步加载原生文件
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static RawFileOperationHandle LoadRawFileAsync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadRawFileAsync(assetInfo);
-		}
-
-		/// <summary>
-		/// 异步加载原生文件
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		public static RawFileOperationHandle LoadRawFileAsync(string location)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadRawFileAsync(location);
-		}
-		#endregion
-
-		#region 场景加载
-		/// <summary>
-		/// 异步加载场景
-		/// </summary>
-		/// <param name="location">场景的定位地址</param>
-		/// <param name="sceneMode">场景加载模式</param>
-		/// <param name="suspendLoad">场景加载到90%自动挂起</param>
-		/// <param name="priority">优先级</param>
-		public static SceneOperationHandle LoadSceneAsync(string location, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, int priority = 100)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSceneAsync(location, sceneMode, suspendLoad, priority);
-		}
-
-		/// <summary>
-		/// 异步加载场景
-		/// </summary>
-		/// <param name="assetInfo">场景的资源信息</param>
-		/// <param name="sceneMode">场景加载模式</param>
-		/// <param name="suspendLoad">场景加载到90%自动挂起</param>
-		/// <param name="priority">优先级</param>
-		public static SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, int priority = 100)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSceneAsync(assetInfo, sceneMode, suspendLoad, priority);
-		}
-		#endregion
-
-		#region 资源加载
-		/// <summary>
-		/// 同步加载资源对象
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static AssetOperationHandle LoadAssetSync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAssetSync(assetInfo);
-		}
-
-		/// <summary>
-		/// 同步加载资源对象
-		/// </summary>
-		/// <typeparam name="TObject">资源类型</typeparam>
-		/// <param name="location">资源的定位地址</param>
-		public static AssetOperationHandle LoadAssetSync<TObject>(string location) where TObject : UnityEngine.Object
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAssetSync<TObject>(location);
-		}
-
-		/// <summary>
-		/// 同步加载资源对象
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		/// <param name="type">资源类型</param>
-		public static AssetOperationHandle LoadAssetSync(string location, System.Type type)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAssetSync(location, type);
-		}
-
-
-		/// <summary>
-		/// 异步加载资源对象
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static AssetOperationHandle LoadAssetAsync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAssetAsync(assetInfo);
-		}
-
-		/// <summary>
-		/// 异步加载资源对象
-		/// </summary>
-		/// <typeparam name="TObject">资源类型</typeparam>
-		/// <param name="location">资源的定位地址</param>
-		public static AssetOperationHandle LoadAssetAsync<TObject>(string location) where TObject : UnityEngine.Object
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAssetAsync<TObject>(location);
-		}
-
-		/// <summary>
-		/// 异步加载资源对象
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		/// <param name="type">资源类型</param>
-		public static AssetOperationHandle LoadAssetAsync(string location, System.Type type)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAssetAsync(location, type);
-		}
-		#endregion
-
-		#region 资源加载
-		/// <summary>
-		/// 同步加载子资源对象
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static SubAssetsOperationHandle LoadSubAssetsSync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSubAssetsSync(assetInfo);
-		}
-
-		/// <summary>
-		/// 同步加载子资源对象
-		/// </summary>
-		/// <typeparam name="TObject">资源类型</typeparam>
-		/// <param name="location">资源的定位地址</param>
-		public static SubAssetsOperationHandle LoadSubAssetsSync<TObject>(string location) where TObject : UnityEngine.Object
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSubAssetsSync<TObject>(location);
-		}
-
-		/// <summary>
-		/// 同步加载子资源对象
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		/// <param name="type">子对象类型</param>
-		public static SubAssetsOperationHandle LoadSubAssetsSync(string location, System.Type type)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSubAssetsSync(location, type);
-		}
-
-
-		/// <summary>
-		/// 异步加载子资源对象
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static SubAssetsOperationHandle LoadSubAssetsAsync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSubAssetsAsync(assetInfo);
-		}
-
-		/// <summary>
-		/// 异步加载子资源对象
-		/// </summary>
-		/// <typeparam name="TObject">资源类型</typeparam>
-		/// <param name="location">资源的定位地址</param>
-		public static SubAssetsOperationHandle LoadSubAssetsAsync<TObject>(string location) where TObject : UnityEngine.Object
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSubAssetsAsync<TObject>(location);
-		}
-
-		/// <summary>
-		/// 异步加载子资源对象
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		/// <param name="type">子对象类型</param>
-		public static SubAssetsOperationHandle LoadSubAssetsAsync(string location, System.Type type)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadSubAssetsAsync(location, type);
-		}
-		#endregion
-
-		#region 资源加载
-		/// <summary>
-		/// 同步加载资源包内所有资源对象
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static AllAssetsOperationHandle LoadAllAssetsSync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAllAssetsSync(assetInfo);
-		}
-
-		/// <summary>
-		/// 同步加载资源包内所有资源对象
-		/// </summary>
-		/// <typeparam name="TObject">资源类型</typeparam>
-		/// <param name="location">资源的定位地址</param>
-		public static AllAssetsOperationHandle LoadAllAssetsSync<TObject>(string location) where TObject : UnityEngine.Object
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAllAssetsSync<TObject>(location);
-		}
-
-		/// <summary>
-		/// 同步加载资源包内所有资源对象
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		/// <param name="type">子对象类型</param>
-		public static AllAssetsOperationHandle LoadAllAssetsSync(string location, System.Type type)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAllAssetsSync(location, type);
-		}
-
-
-		/// <summary>
-		/// 异步加载资源包内所有资源对象
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		public static AllAssetsOperationHandle LoadAllAssetsAsync(AssetInfo assetInfo)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAllAssetsAsync(assetInfo);
-		}
-
-		/// <summary>
-		/// 异步加载资源包内所有资源对象
-		/// </summary>
-		/// <typeparam name="TObject">资源类型</typeparam>
-		/// <param name="location">资源的定位地址</param>
-		public static AllAssetsOperationHandle LoadAllAssetsAsync<TObject>(string location) where TObject : UnityEngine.Object
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAllAssetsAsync<TObject>(location);
-		}
-
-		/// <summary>
-		/// 异步加载资源包内所有资源对象
-		/// </summary>
-		/// <param name="location">资源的定位地址</param>
-		/// <param name="type">子对象类型</param>
-		public static AllAssetsOperationHandle LoadAllAssetsAsync(string location, System.Type type)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.LoadAllAssetsAsync(location, type);
-		}
-		#endregion
-
-		#region 资源下载
-		/// <summary>
-		/// 创建资源下载器,用于下载当前资源版本所有的资源包文件
-		/// </summary>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateResourceDownloader(int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateResourceDownloader(downloadingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建资源下载器,用于下载指定的资源标签关联的资源包文件
-		/// </summary>
-		/// <param name="tag">资源标签</param>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateResourceDownloader(string tag, int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateResourceDownloader(new string[] { tag }, downloadingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建资源下载器,用于下载指定的资源标签列表关联的资源包文件
-		/// </summary>
-		/// <param name="tags">资源标签列表</param>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateResourceDownloader(string[] tags, int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateResourceDownloader(tags, downloadingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建资源下载器,用于下载指定的资源依赖的资源包文件
-		/// </summary>
-		/// <param name="location">资源定位地址</param>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateBundleDownloader(string location, int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateBundleDownloader(location, downloadingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建资源下载器,用于下载指定的资源列表依赖的资源包文件
-		/// </summary>
-		/// <param name="locations">资源定位地址列表</param>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateBundleDownloader(string[] locations, int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateBundleDownloader(locations, downloadingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建资源下载器,用于下载指定的资源依赖的资源包文件
-		/// </summary>
-		/// <param name="assetInfo">资源信息</param>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateBundleDownloader(AssetInfo assetInfo, int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateBundleDownloader(assetInfo, downloadingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建资源下载器,用于下载指定的资源列表依赖的资源包文件
-		/// </summary>
-		/// <param name="assetInfos">资源信息列表</param>
-		/// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
-		/// <param name="failedTryAgain">下载失败的重试次数</param>
-		public static ResourceDownloaderOperation CreateBundleDownloader(AssetInfo[] assetInfos, int downloadingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateBundleDownloader(assetInfos, downloadingMaxNumber, failedTryAgain);
-		}
-		#endregion
-
-		#region 资源解压
-		/// <summary>
-		/// 创建内置资源解压器
-		/// </summary>
-		/// <param name="tag">资源标签</param>
-		/// <param name="unpackingMaxNumber">同时解压的最大文件数</param>
-		/// <param name="failedTryAgain">解压失败的重试次数</param>
-		public static ResourceUnpackerOperation CreateResourceUnpacker(string tag, int unpackingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateResourceUnpacker(tag, unpackingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建内置资源解压器
-		/// </summary>
-		/// <param name="tags">资源标签列表</param>
-		/// <param name="unpackingMaxNumber">同时解压的最大文件数</param>
-		/// <param name="failedTryAgain">解压失败的重试次数</param>
-		public static ResourceUnpackerOperation CreateResourceUnpacker(string[] tags, int unpackingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateResourceUnpacker(tags, unpackingMaxNumber, failedTryAgain);
-		}
-
-		/// <summary>
-		/// 创建内置资源解压器
-		/// </summary>
-		/// <param name="unpackingMaxNumber">同时解压的最大文件数</param>
-		/// <param name="failedTryAgain">解压失败的重试次数</param>
-		public static ResourceUnpackerOperation CreateResourceUnpacker(int unpackingMaxNumber, int failedTryAgain)
-		{
-			DebugCheckDefaultPackageValid();
-			return _defaultPackage.CreateResourceUnpacker(unpackingMaxNumber, failedTryAgain);
-		}
-		#endregion
-
-		#region 调试方法
-		[Conditional("DEBUG")]
-		private static void DebugCheckDefaultPackageValid()
-		{
-			if (_defaultPackage == null)
-				throw new Exception($"Default package is null. Please use {nameof(YooAssets.SetDefaultPackage)} !");
-		}
-		#endregion
-	}
+    public static partial class YooAssets
+    {
+        private static ResourcePackage _defaultPackage;
+
+        /// <summary>
+        /// 设置默认的资源包
+        /// </summary>
+        public static void SetDefaultPackage(ResourcePackage package)
+        {
+            _defaultPackage = package;
+        }
+
+        #region 资源信息
+
+        /// <summary>
+        /// 是否需要从远端更新下载
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        public static bool IsNeedDownloadFromRemote(string location)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.IsNeedDownloadFromRemote(location);
+        }
+
+        /// <summary>
+        /// 是否需要从远端更新下载
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        public static bool IsNeedDownloadFromRemote(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.IsNeedDownloadFromRemote(assetInfo);
+        }
+
+        /// <summary>
+        /// 获取资源信息列表
+        /// </summary>
+        /// <param name="tag">资源标签</param>
+        public static AssetInfo[] GetAssetInfos(string tag)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.GetAssetInfos(tag);
+        }
+
+        /// <summary>
+        /// 获取资源信息列表
+        /// </summary>
+        /// <param name="tags">资源标签列表</param>
+        public static AssetInfo[] GetAssetInfos(string[] tags)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.GetAssetInfos(tags);
+        }
+
+        /// <summary>
+        /// 获取资源信息
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        public static AssetInfo GetAssetInfo(string location)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.GetAssetInfo(location);
+        }
+
+        /// <summary>
+        /// 检查资源定位地址是否有效
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        public static bool CheckLocationValid(string location)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CheckLocationValid(location);
+        }
+
+        #endregion
+
+        #region 原生文件
+
+        /// <summary>
+        /// 同步加载原生文件
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static RawFileOperationHandle LoadRawFileSync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadRawFileSync(assetInfo);
+        }
+
+        /// <summary>
+        /// 同步加载原生文件
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        public static RawFileOperationHandle LoadRawFileSync(string location)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadRawFileSync(location);
+        }
+
+        /// <summary>
+        /// 异步加载原生文件
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static RawFileOperationHandle LoadRawFileAsync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadRawFileAsync(assetInfo);
+        }
+
+        /// <summary>
+        /// 异步加载原生文件
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        public static RawFileOperationHandle LoadRawFileAsync(string location)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadRawFileAsync(location);
+        }
+
+        #endregion
+
+        #region 场景加载
+
+        /// <summary>
+        /// 异步加载场景
+        /// </summary>
+        /// <param name="location">场景的定位地址</param>
+        /// <param name="sceneMode">场景加载模式</param>
+        /// <param name="suspendLoad">场景加载到90%自动挂起</param>
+        /// <param name="priority">优先级</param>
+        public static SceneOperationHandle LoadSceneAsync(string location,
+            LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, int priority = 100)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSceneAsync(location, sceneMode, suspendLoad, priority);
+        }
+
+        /// <summary>
+        /// 异步加载场景
+        /// </summary>
+        /// <param name="assetInfo">场景的资源信息</param>
+        /// <param name="sceneMode">场景加载模式</param>
+        /// <param name="suspendLoad">场景加载到90%自动挂起</param>
+        /// <param name="priority">优先级</param>
+        public static SceneOperationHandle LoadSceneAsync(AssetInfo assetInfo,
+            LoadSceneMode sceneMode = LoadSceneMode.Single, bool suspendLoad = false, int priority = 100)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSceneAsync(assetInfo, sceneMode, suspendLoad, priority);
+        }
+
+        #endregion
+
+        #region 资源加载
+
+        // /// <summary>
+        // /// 同步加载资源对象
+        // /// </summary>
+        // /// <param name="assetInfo">资源信息</param>
+        // public static AssetOperationHandle LoadAssetSync(AssetInfo assetInfo)
+        // {
+        // 	DebugCheckDefaultPackageValid();
+        // 	return _defaultPackage.LoadAssetSync(assetInfo);
+        // }
+
+        // /// <summary>
+        // /// 同步加载资源对象
+        // /// </summary>
+        // /// <typeparam name="TObject">资源类型</typeparam>
+        // /// <param name="location">资源的定位地址</param>
+        // public static AssetOperationHandle LoadAssetSync<TObject>(string location) where TObject : UnityEngine.Object
+        // {
+        // 	DebugCheckDefaultPackageValid();
+        // 	return _defaultPackage.LoadAssetSync<TObject>(location);
+        // }
+
+        // /// <summary>
+        // /// 同步加载资源对象
+        // /// </summary>
+        // /// <param name="location">资源的定位地址</param>
+        // /// <param name="type">资源类型</param>
+        // public static AssetOperationHandle LoadAssetSync(string location, System.Type type)
+        // {
+        // 	DebugCheckDefaultPackageValid();
+        // 	return _defaultPackage.LoadAssetSync(location, type);
+        // }
+
+
+        /// <summary>
+        /// 异步加载资源对象
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static AssetOperationHandle LoadAssetAsync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAssetAsync(assetInfo);
+        }
+
+        /// <summary>
+        /// 异步加载资源对象
+        /// </summary>
+        /// <typeparam name="TObject">资源类型</typeparam>
+        /// <param name="location">资源的定位地址</param>
+        public static AssetOperationHandle LoadAssetAsync<TObject>(string location) where TObject : UnityEngine.Object
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAssetAsync<TObject>(location);
+        }
+
+        /// <summary>
+        /// 异步加载资源对象
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        /// <param name="type">资源类型</param>
+        public static AssetOperationHandle LoadAssetAsync(string location, System.Type type)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAssetAsync(location, type);
+        }
+
+        #endregion
+
+        #region 资源加载
+
+        /// <summary>
+        /// 同步加载子资源对象
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static SubAssetsOperationHandle LoadSubAssetsSync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSubAssetsSync(assetInfo);
+        }
+
+        /// <summary>
+        /// 同步加载子资源对象
+        /// </summary>
+        /// <typeparam name="TObject">资源类型</typeparam>
+        /// <param name="location">资源的定位地址</param>
+        public static SubAssetsOperationHandle LoadSubAssetsSync<TObject>(string location)
+            where TObject : UnityEngine.Object
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSubAssetsSync<TObject>(location);
+        }
+
+        /// <summary>
+        /// 同步加载子资源对象
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        /// <param name="type">子对象类型</param>
+        public static SubAssetsOperationHandle LoadSubAssetsSync(string location, System.Type type)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSubAssetsSync(location, type);
+        }
+
+
+        /// <summary>
+        /// 异步加载子资源对象
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static SubAssetsOperationHandle LoadSubAssetsAsync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSubAssetsAsync(assetInfo);
+        }
+
+        /// <summary>
+        /// 异步加载子资源对象
+        /// </summary>
+        /// <typeparam name="TObject">资源类型</typeparam>
+        /// <param name="location">资源的定位地址</param>
+        public static SubAssetsOperationHandle LoadSubAssetsAsync<TObject>(string location)
+            where TObject : UnityEngine.Object
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSubAssetsAsync<TObject>(location);
+        }
+
+        /// <summary>
+        /// 异步加载子资源对象
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        /// <param name="type">子对象类型</param>
+        public static SubAssetsOperationHandle LoadSubAssetsAsync(string location, System.Type type)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadSubAssetsAsync(location, type);
+        }
+
+        #endregion
+
+        #region 资源加载
+
+        /// <summary>
+        /// 同步加载资源包内所有资源对象
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static AllAssetsOperationHandle LoadAllAssetsSync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAllAssetsSync(assetInfo);
+        }
+
+        /// <summary>
+        /// 同步加载资源包内所有资源对象
+        /// </summary>
+        /// <typeparam name="TObject">资源类型</typeparam>
+        /// <param name="location">资源的定位地址</param>
+        public static AllAssetsOperationHandle LoadAllAssetsSync<TObject>(string location)
+            where TObject : UnityEngine.Object
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAllAssetsSync<TObject>(location);
+        }
+
+        /// <summary>
+        /// 同步加载资源包内所有资源对象
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        /// <param name="type">子对象类型</param>
+        public static AllAssetsOperationHandle LoadAllAssetsSync(string location, System.Type type)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAllAssetsSync(location, type);
+        }
+
+
+        /// <summary>
+        /// 异步加载资源包内所有资源对象
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        public static AllAssetsOperationHandle LoadAllAssetsAsync(AssetInfo assetInfo)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAllAssetsAsync(assetInfo);
+        }
+
+        /// <summary>
+        /// 异步加载资源包内所有资源对象
+        /// </summary>
+        /// <typeparam name="TObject">资源类型</typeparam>
+        /// <param name="location">资源的定位地址</param>
+        public static AllAssetsOperationHandle LoadAllAssetsAsync<TObject>(string location)
+            where TObject : UnityEngine.Object
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAllAssetsAsync<TObject>(location);
+        }
+
+        /// <summary>
+        /// 异步加载资源包内所有资源对象
+        /// </summary>
+        /// <param name="location">资源的定位地址</param>
+        /// <param name="type">子对象类型</param>
+        public static AllAssetsOperationHandle LoadAllAssetsAsync(string location, System.Type type)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.LoadAllAssetsAsync(location, type);
+        }
+
+        #endregion
+
+        #region 资源下载
+
+        /// <summary>
+        /// 创建资源下载器,用于下载当前资源版本所有的资源包文件
+        /// </summary>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateResourceDownloader(int downloadingMaxNumber, int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateResourceDownloader(downloadingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建资源下载器,用于下载指定的资源标签关联的资源包文件
+        /// </summary>
+        /// <param name="tag">资源标签</param>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateResourceDownloader(string tag, int downloadingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateResourceDownloader(new string[] { tag }, downloadingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建资源下载器,用于下载指定的资源标签列表关联的资源包文件
+        /// </summary>
+        /// <param name="tags">资源标签列表</param>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateResourceDownloader(string[] tags, int downloadingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateResourceDownloader(tags, downloadingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建资源下载器,用于下载指定的资源依赖的资源包文件
+        /// </summary>
+        /// <param name="location">资源定位地址</param>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateBundleDownloader(string location, int downloadingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateBundleDownloader(location, downloadingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建资源下载器,用于下载指定的资源列表依赖的资源包文件
+        /// </summary>
+        /// <param name="locations">资源定位地址列表</param>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateBundleDownloader(string[] locations, int downloadingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateBundleDownloader(locations, downloadingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建资源下载器,用于下载指定的资源依赖的资源包文件
+        /// </summary>
+        /// <param name="assetInfo">资源信息</param>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateBundleDownloader(AssetInfo assetInfo, int downloadingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateBundleDownloader(assetInfo, downloadingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建资源下载器,用于下载指定的资源列表依赖的资源包文件
+        /// </summary>
+        /// <param name="assetInfos">资源信息列表</param>
+        /// <param name="downloadingMaxNumber">同时下载的最大文件数</param>
+        /// <param name="failedTryAgain">下载失败的重试次数</param>
+        public static ResourceDownloaderOperation CreateBundleDownloader(AssetInfo[] assetInfos,
+            int downloadingMaxNumber, int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateBundleDownloader(assetInfos, downloadingMaxNumber, failedTryAgain);
+        }
+
+        #endregion
+
+        #region 资源解压
+
+        /// <summary>
+        /// 创建内置资源解压器
+        /// </summary>
+        /// <param name="tag">资源标签</param>
+        /// <param name="unpackingMaxNumber">同时解压的最大文件数</param>
+        /// <param name="failedTryAgain">解压失败的重试次数</param>
+        public static ResourceUnpackerOperation CreateResourceUnpacker(string tag, int unpackingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateResourceUnpacker(tag, unpackingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建内置资源解压器
+        /// </summary>
+        /// <param name="tags">资源标签列表</param>
+        /// <param name="unpackingMaxNumber">同时解压的最大文件数</param>
+        /// <param name="failedTryAgain">解压失败的重试次数</param>
+        public static ResourceUnpackerOperation CreateResourceUnpacker(string[] tags, int unpackingMaxNumber,
+            int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateResourceUnpacker(tags, unpackingMaxNumber, failedTryAgain);
+        }
+
+        /// <summary>
+        /// 创建内置资源解压器
+        /// </summary>
+        /// <param name="unpackingMaxNumber">同时解压的最大文件数</param>
+        /// <param name="failedTryAgain">解压失败的重试次数</param>
+        public static ResourceUnpackerOperation CreateResourceUnpacker(int unpackingMaxNumber, int failedTryAgain)
+        {
+            DebugCheckDefaultPackageValid();
+            return _defaultPackage.CreateResourceUnpacker(unpackingMaxNumber, failedTryAgain);
+        }
+
+        #endregion
+
+        #region 调试方法
+
+        [Conditional("DEBUG")]
+        private static void DebugCheckDefaultPackageValid()
+        {
+            if (_defaultPackage == null)
+                throw new Exception($"Default package is null. Please use {nameof(YooAssets.SetDefaultPackage)} !");
+        }
+
+        #endregion
+    }
 }

+ 2 - 0
GameClient/GameClient.sln.DotSettings.user

@@ -1,6 +1,8 @@
 <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAction_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F695d1cc93cca45069c528c15c9fdd7493e2800_003F01_003F46970b32_003FAction_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AActivator_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F3789ee403a53437cbb6b5d9ab6311f51573620_003F56_003F27c54aae_003FActivator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AActivator_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F695d1cc93cca45069c528c15c9fdd7493e2800_003F20_003F3a0a5fc0_003FActivator_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArraySortHelper_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F695d1cc93cca45069c528c15c9fdd7493e2800_003Fe0_003F4c18b32c_003FArraySortHelper_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABuildResult_002Ecs_002Fl_003AC_0021_003FUsers_003Fadmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8d4895b259be41298a685a0c9b42357576b400_003Fa9_003Fbef924de_003FBuildResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEditorUtility_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8d4895b259be41298a685a0c9b42357576b400_003F3f_003Fa805acc1_003FEditorUtility_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFile_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F695d1cc93cca45069c528c15c9fdd7493e2800_003Fc3_003F83d8926e_003FFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>