소스 검색

增加了GameObjectPool,单位模型和特效实现池化

大爷 2 년 전
부모
커밋
6c49249938
20개의 변경된 파일306개의 추가작업 그리고 194개의 파일을 삭제
  1. 2 1
      Unity/Assets/Scripts/Codes/Hotfix/Client/EntryEvent2_InitClient.cs
  2. 1 1
      Unity/Assets/Scripts/Codes/Hotfix/Client/Login/EnterMapHelper.cs
  3. 1 3
      Unity/Assets/Scripts/Codes/Hotfix/Client/Scene/SceneChangeHelper.cs
  4. 2 3
      Unity/Assets/Scripts/Codes/Hotfix/Client/Scene/SceneFactory.cs
  5. 3 22
      Unity/Assets/Scripts/Codes/Hotfix/Client/battle/UnitMgr.cs
  6. 0 28
      Unity/Assets/Scripts/Codes/Hotfix/Client/battle/unit/BattleActor.cs
  7. 1 1
      Unity/Assets/Scripts/Codes/Hotfix/Client/battle/unit/BattleObject.cs
  8. 4 54
      Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectMgr.cs
  9. 0 14
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateClientScene_AddComponent.cs
  10. 0 11
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateClientScene_AddComponent.cs.meta
  11. 1 3
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateCurrentScene_AddComponent.cs
  12. 237 0
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/GameObjectPool.cs
  13. 0 25
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/ModelViewComponentSystem.cs
  14. 0 11
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/ModelViewComponentSystem.cs.meta
  15. 2 0
      Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/SceneChangeStart_AddComponent.cs
  16. 10 2
      Unity/Assets/Scripts/Codes/HotfixView/Client/Unit/OnDestroyZoneObject.cs
  17. 14 15
      Unity/Assets/Scripts/Codes/HotfixView/Client/Unit/OnNewZoneObject.cs
  18. 5 0
      Unity/Assets/Scripts/Codes/HotfixView/Client/Unit/UnitRenderSystem.cs
  19. 22 0
      Unity/Assets/Scripts/Codes/ModelView/Client/Unit/ModelViewComponent.cs
  20. 1 0
      Unity/Assets/Scripts/Codes/Mono/AnimationData.cs

+ 2 - 1
Unity/Assets/Scripts/Codes/Hotfix/Client/EntryEvent2_InitClient.cs

@@ -7,9 +7,10 @@
         {
             //加载战斗相关资源
             Game.AddSingleton<BattleResourceMgr>();
-            Game.AddSingleton<BattleMgr>();
             Game.AddSingleton<BattleUnitFactory>();
             Game.AddSingleton<SkillMgr>();
+            Game.AddSingleton<UnitMgr>();
+            Game.AddSingleton<BattleMgr>();
 
             await ETTask.CompletedTask;
         }

+ 1 - 1
Unity/Assets/Scripts/Codes/Hotfix/Client/Login/EnterMapHelper.cs

@@ -28,7 +28,7 @@ namespace ET.Client
                 // 等待场景切换完成
                 await clientScene.GetComponent<ObjectWait>().Wait<Wait_SceneChangeFinish>();
                 //告诉战斗服 i am ready
-                //clientScene.GetComponent<SessionComponent>().Session.Send(new BattleClientReady());
+                clientScene.GetComponent<SessionComponent>().Session.Send(new BattleClientReady());
             }
             catch (Exception e)
             {

+ 1 - 3
Unity/Assets/Scripts/Codes/Hotfix/Client/Scene/SceneChangeHelper.cs

@@ -5,11 +5,9 @@
         // 场景切换协程
         public static async ETTask SceneChangeTo(Scene clientScene, string sceneName, long sceneInstanceId)
         {
-            clientScene.RemoveComponent<AIComponent>();
-            
             CurrentScenesComponent currentScenesComponent = clientScene.GetComponent<CurrentScenesComponent>();
             currentScenesComponent.Scene?.Dispose(); // 删除之前的CurrentScene,创建新的
-            Scene currentScene = SceneFactory.CreateCurrentScene(sceneInstanceId, clientScene.Zone, sceneName, currentScenesComponent);
+            SceneFactory.CreateCurrentScene(sceneInstanceId, clientScene.Zone, sceneName, currentScenesComponent);
          
             // 可以订阅这个事件中创建Loading界面
             EventSystem.Instance.Publish(clientScene, new EventType.SceneChangeStart());

+ 2 - 3
Unity/Assets/Scripts/Codes/Hotfix/Client/Scene/SceneFactory.cs

@@ -1,4 +1,4 @@
-using System.Net.Sockets;
+using System.Net.Sockets;
 
 namespace ET.Client
 {
@@ -13,7 +13,6 @@ namespace ET.Client
             clientScene.AddComponent<ObjectWait>();
             clientScene.AddComponent<PlayerComponent>();
             
-            EventSystem.Instance.Publish(clientScene, new EventType.AfterCreateClientScene());
             return clientScene;
         }
         
@@ -28,4 +27,4 @@ namespace ET.Client
         
         
     }
-}
+}

+ 3 - 22
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/UnitMgr.cs

@@ -3,11 +3,8 @@ using CommonLang;
 
 namespace ET.Client
 {
-    [ComponentOf(typeof(Scene))]
-    public class UnitMgr : Entity, IAwake, IDestroy
+    public class UnitMgr : Singleton<UnitMgr>
     {
-        public static UnitMgr Instance;
-
         public BattleActor Actor { get; set; }
         public uint ActorId
         {
@@ -56,26 +53,10 @@ namespace ET.Client
             }
             UnitList.Clear();
         }
-    }
-
-    [ObjectSystem]
-    public class UnitMgrAwakeSystem : AwakeSystem<UnitMgr>
-    {
-        protected override void Awake(UnitMgr self)
-        {
-            UnitMgr.Instance = self;
-            self.RecycleUnits();
-        }
-    }
 
-    [ObjectSystem]
-    public class UnitMgrDestroySystem : DestroySystem<UnitMgr>
-    {
-        protected override void Destroy(UnitMgr self)
+        public void Clear()
         {
-            self.RecycleUnits();
-            UnitMgr.Instance = null;
+            UnitList.Clear();
         }
     }
-
 }

+ 0 - 28
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/unit/BattleActor.cs

@@ -8,34 +8,6 @@ using ProtoBuf;
 using System.ComponentModel;
 using XmdsCommon.Plugin;
 
-public partial class SkillKeyStruct : ProtoObject
-{
-    [ProtoMember(1)]
-    public int keyPos { get; set; }
-
-    [ProtoMember(2)]
-    public int baseSkillId { get; set; }
-
-    [ProtoMember(3)]
-    public int advancedSkillId { get; set; }
-
-    [ProtoMember(4)]
-    public string icon { get; set; }
-
-    [ProtoMember(5)]
-    public int flag { get; set; }
-
-    [ProtoMember(6)]
-    public int unlockLevel { get; set; }
-
-    [ProtoMember(7)]
-    public string name { get; set; }
-
-    [ProtoMember(8)]
-    public string baseSkillIcon { get; set; }
-
-}
-
 [Event(SceneType.None)]
 public class LaunchSkillEventHandler : BEvent<LaunchSkillEvent>
 {

+ 1 - 1
Unity/Assets/Scripts/Codes/Hotfix/Client/battle/unit/BattleObject.cs

@@ -32,7 +32,7 @@ public class BattleObject
         {
             if (_CurrentSceneCache == null)
             {
-                var cs = ClientSceneManagerComponent.Instance.GetChild<Scene>(UnitMgr.Instance.DomainZone());
+                var cs = PlayerComponent.Instance.ClientScene();
                 _CurrentSceneCache = cs.GetComponent<CurrentScenesComponent>().Scene;
             }
             return _CurrentSceneCache;

+ 4 - 54
Unity/Assets/Scripts/Codes/HotfixView/Client/Effect/EffectMgr.cs

@@ -1,7 +1,4 @@
 using CommonAI.Zone;
-using System;
-using System.Collections.Generic;
-using CommonAI.ZoneClient;
 using UnityEngine;
 using System.Text.RegularExpressions;
 using CommonLang;
@@ -25,7 +22,7 @@ namespace ET.Client
     public class EffectMgr : Singleton<EffectMgr>, ISingletonAwake, ISingletonUpdate
     {
         private HashMap<uint, EffectPlayInfo> playingList = new();
-        private HashMap<string, List<GameObject>> effectPool = new();
+        
         private static Vector3 vecTemp = new();
 
         public void Awake()
@@ -51,7 +48,6 @@ namespace ET.Client
             GameObject go = null;
             if (!effect.Name.IsNullOrWhitespace())
             {
-                go = await loadEffect(effect.Name);
                 UnitRenderComponet render = null;
                 if (effect.BindBody)
                 {
@@ -59,11 +55,11 @@ namespace ET.Client
                     if (render == null)
                     {
                         Log.Debug($"ignore unit effect: {effect.Name}@{HostId}, cause of No Render");
-                        recycleEffect(go);
                         return 0;
                     }
                 }
 
+                go = await GameObjectPool.Instance.Acquire("Effect_" + effect.Name);
                 var timeComponent = go.GetComponent<EffectTime>();
                 if (time == 0f) time = timeComponent.duration;
                 if (time < 0f) time = EffectPlayInfo.TIME_FOREVER;
@@ -148,6 +144,7 @@ namespace ET.Client
                     }
                 }
             }
+            go.SetActive(true);
         }
 
         public void Clear()
@@ -157,15 +154,6 @@ namespace ET.Client
                 GameObject.Destroy(epi.GameObj);
             }
             playingList.Clear();
-
-            foreach (var list in effectPool.Values)
-            {
-                foreach (var go in list)
-                {
-                    GameObject.Destroy(go);
-                }
-            }
-            effectPool.Clear();
         }
 
         public void RemoveEffect(uint id)
@@ -174,45 +162,7 @@ namespace ET.Client
             {
                 var info = playingList[id];
                 playingList.Remove(id);
-                recycleEffect(info.GameObj);
-            }
-        }
-
-        private async ETTask<GameObject> loadEffect(string prefabName)
-        {
-            if (effectPool.TryGetValue(prefabName, out var golist))
-            {
-                if (golist.Count > 0)
-                {
-                    var gobj = golist[0];
-                    golist.RemoveRange(0, 1);
-                    return gobj;
-                }
-            }
-            else
-            {
-                effectPool.Add(prefabName, new List<GameObject>());
-            }
-
-            var handle = await YooAssetProxy.LoadAssetAsync<GameObject>($"Effect_{prefabName}");
-            var prefab = handle.GetAssetObject<GameObject>();
-            var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.Unit, true);
-            gameobj.name = prefabName;
-            return gameobj;
-        }
-
-        private void recycleEffect(GameObject go)
-        {
-            go.SetActive(false);
-            go.transform.SetParent(GlobalViewComponent.Instance.RecycleNode, false);
-            var name = go.name;
-            if (effectPool.TryGetValue(name, out var golist))
-            {
-                golist.Add(go);
-            }
-            else
-            {
-                effectPool.Add(name, new List<GameObject>() { go });
+                GameObjectPool.Instance.RecycleObject(info.GameObj);
             }
         }
     }

+ 0 - 14
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateClientScene_AddComponent.cs

@@ -1,14 +0,0 @@
-/*namespace ET.Client
-{
-    [Event(SceneType.Client)]
-    public class AfterCreateClientScene_AddComponent: AEvent<EventType.AfterCreateClientScene>
-    {
-        protected override async ETTask Run(Scene scene, EventType.AfterCreateClientScene args)
-        {
-            //scene.AddComponent<UIEventComponent>();
-            //scene.AddComponent<UIComponent>();
-            //scene.AddComponent<ResourcesLoaderComponent>();
-            await ETTask.CompletedTask;
-        }
-    }
-}*/

+ 0 - 11
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateClientScene_AddComponent.cs.meta

@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: dfedbb9bd8366d04681856b0f85a9020
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 1 - 3
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/AfterCreateCurrentScene_AddComponent.cs

@@ -5,10 +5,8 @@
     {
         protected override async ETTask Run(Scene scene, EventType.AfterCreateCurrentScene args)
         {
-            //scene.AddComponent<UIComponent>();
-            //scene.AddComponent<ResourcesLoaderComponent>();
+            scene.AddComponent<GameObjectPool>();
             scene.AddComponent<ModelViewComponent>();
-            scene.AddComponent<UnitMgr>();
             await ETTask.CompletedTask;
         }
     }

+ 237 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/GameObjectPool.cs

@@ -0,0 +1,237 @@
+using CommonAI.Zone;
+using CommonLang;
+using Sirenix.Utilities;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace ET.Client
+{
+    [FriendOf(typeof(GameObjectPool))]
+    public static class GameObjectPoolSystem
+    {
+        [ObjectSystem]
+        public class GameObjectPoolAwakeSystem : AwakeSystem<GameObjectPool>
+        {
+            protected override void Awake(GameObjectPool self)
+            {
+                GameObjectPool.Instance = self;
+            }
+        }
+
+        [ObjectSystem]
+        public class GameObjectPoolDestroySystem : DestroySystem<GameObjectPool>
+        {
+            protected override void Destroy(GameObjectPool self)
+            {
+                self.ClearCache();
+                GameObjectPool.Instance = null;
+            }
+        }
+    }
+
+    [ComponentOf(typeof(Scene))]
+    public class GameObjectPool : Entity, IAwake, IDestroy
+    {
+        [StaticField]
+        public static GameObjectPool Instance;
+
+        private readonly HashMap<string, List<GameObject>> goPool = new();
+
+        //TODO: 选取当前场景的单位、技能(事件触发等等)
+        //TODO: BUFF
+        public async ETTask CacheSceneObject(/*int scnId*/)
+        {
+            var templates = BattleResourceMgr.Instance.GameEditorTemplates.Templates;
+
+            //遍历模型
+            var units = templates.getUnits();
+            foreach(var unit in units.Values)
+            {
+                var name = $"Unit_{unit.FileName}";
+                var handle = await YooAssetProxy.LoadAssetAsync<GameObject>(name);
+                var prefab = handle.GetAssetObject<GameObject>();
+                var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.RecycleNode, true);
+                gameobj.name = name;
+                RecycleObject(gameobj);
+            }
+
+            List<string> effectlist = new();
+            var skills = templates.getAllSkillData();
+            foreach (var skt in skills.Values)
+            {
+                foreach (var act in skt.ActionQueue)
+                {
+                    if (!act.ActionEffectFileName.IsNullOrWhitespace())
+                    {
+                        effectlist.Add(act.ActionEffectFileName);
+                    }
+                    foreach (var kf in act.KeyFrames)
+                    {
+                        if (kf.Effect != null && !kf.Effect.Name.IsNullOrWhitespace())
+                        {
+                            effectlist.Add(kf.Effect.Name);
+                        }
+                        if (kf.Spell != null)
+                        {
+                            CacheSpellEffect(templates, kf.Spell.SpellID, ref effectlist);
+                        }
+                    }
+                }
+            }
+
+            foreach (var ef in effectlist)
+            {
+                var name = $"Effect_{ef}";
+                var handle = await YooAssetProxy.LoadAssetAsync<GameObject>(name);
+                var prefab = handle.GetAssetObject<GameObject>();
+                var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.RecycleNode, true);
+                gameobj.name = name;
+                RecycleObject(gameobj);
+            }
+        }
+
+        private void CacheSpellEffect(TemplateManager templates, int spellid, ref List<string> effectlist)
+        {
+            var spell = templates.getSpell(spellid);
+            if (spell == null)
+            {
+                Log.Error($"spell({spellid}) not exist");
+                return;
+            }
+            if (!spell.FileName.IsNullOrWhitespace())
+            {
+                effectlist.Add(spell.FileName);
+            }
+
+            var frame = spell.HitIntervalKeyFrame;
+            if (frame != null)
+            {
+                if (frame.Effect != null && !frame.Effect.Name.IsNullOrWhitespace())
+                {
+                    effectlist.Add(frame.Effect.Name);
+                }
+                if (frame.Spell != null && frame.Spell.SpellID != 0)
+                {
+                    CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist);
+                }
+                if (frame.Attack != null)
+                {
+                    var attack = frame.Attack;
+                    if (attack.Effect != null && !attack.Effect.Name.IsNullOrWhitespace())
+                    {
+                        effectlist.Add(attack.Effect.Name);
+                    }
+                    if (attack.Spell != null && attack.Spell.SpellID != 0)
+                    {
+                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist);
+                    }
+                }
+            }
+
+            frame = spell.HitOnExplosionKeyFrame;
+            if (spell.HitOnExplosion && frame != null)
+            {
+                if (frame.Effect != null && !frame.Effect.Name.IsNullOrWhitespace())
+                {
+                    effectlist.Add(frame.Effect.Name);
+                }
+                if (frame.Spell != null && frame.Spell.SpellID != 0)
+                {
+                    CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist);
+                }
+                if (frame.Attack != null)
+                {
+                    var attack = frame.Attack;
+                    if (attack.Effect != null && !attack.Effect.Name.IsNullOrWhitespace())
+                    {
+                        effectlist.Add(attack.Effect.Name);
+                    }
+                    if (attack.Spell != null && attack.Spell.SpellID != 0)
+                    {
+                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist);
+                    }
+                }
+            }
+
+            foreach (var frm in spell.KeyFrames)
+            {
+                if (frm.Effect != null && !frm.Effect.Name.IsNullOrWhitespace())
+                {
+                    effectlist.Add(frm.Effect.Name);
+                }
+                if (frm.Spell != null && frame.Spell.SpellID != 0)
+                {
+                    CacheSpellEffect(templates, frm.Spell.SpellID, ref effectlist);
+                }
+                if (frm.Attack != null)
+                {
+                    var attack = frm.Attack;
+                    if (attack.Effect != null && !attack.Effect.Name.IsNullOrWhitespace())
+                    {
+                        effectlist.Add(attack.Effect.Name);
+                    }
+                    if (attack.Spell != null && attack.Spell.SpellID != 0)
+                    {
+                        CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist);
+                    }
+                }
+            }
+        }
+
+        public void ClearCache()
+        {
+            foreach (var list in goPool.Values)
+            {
+                foreach (var go in list)
+                {
+                    GameObject.Destroy(go);
+                }
+            }
+            goPool.Clear();
+        }
+
+        public void RecycleObject(GameObject go, string key = "")
+        {
+            if(key.IsNullOrWhitespace())
+            {
+                key = go.name;
+            }
+            Log.Debug($"cache gameobject: {key}");
+            go.SetActive(false);
+            go.transform.SetParent(GlobalViewComponent.Instance.RecycleNode, false);
+            if (goPool.TryGetValue(key, out var golist))
+            {
+                golist.Add(go);
+            }
+            else
+            {
+                goPool.Add(key, new List<GameObject>() { go });
+            }
+        }
+
+        public async ETTask<GameObject> Acquire(string key)
+        {
+            if (goPool.TryGetValue(key, out var golist))
+            {
+                if (golist.Count > 0)
+                {
+                    Log.Debug($"got gameobject ({key}) from pool");
+                    var gobj = golist[0];
+                    golist.RemoveRange(0, 1);
+                    return gobj;
+                }
+            }
+            else
+            {
+                goPool.Add(key, new List<GameObject>());
+            }
+            Log.Debug($"new gameobject: ({key})");
+
+            var handle = await YooAssetProxy.LoadAssetAsync<GameObject>(key);
+            var prefab = handle.GetAssetObject<GameObject>();
+            var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.RecycleNode, true);
+            gameobj.name = key;
+            return gameobj;
+        }
+    }
+}

+ 0 - 25
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/ModelViewComponentSystem.cs

@@ -1,25 +0,0 @@
-
-namespace ET.Client
-{
-    [FriendOf(typeof(ModelViewComponent))]
-    public static class ModelViewComponentSystem
-    {
-        [ObjectSystem]
-        public class ModelViewComponentAwakeSystem : AwakeSystem<ModelViewComponent>
-        {
-            protected override void Awake(ModelViewComponent self)
-            {
-                ModelViewComponent.Instance = self;
-            }
-        }
-
-        [ObjectSystem]
-        public class ModelViewComponentDestroySystem : DestroySystem<ModelViewComponent>
-        {
-            protected override void Destroy(ModelViewComponent self)
-            {
-                ModelViewComponent.Instance = null;
-            }
-        }
-    }
-}

+ 0 - 11
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/ModelViewComponentSystem.cs.meta

@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: a4ba134d81bdf404f923c74c5670880d
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 2 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Scene/SceneChangeStart_AddComponent.cs

@@ -20,6 +20,8 @@ namespace ET.Client
             UIHelper.SetVisible("Loading", false);
             currentScene.AddComponent<OperaComponent>();
 
+            await GameObjectPool.Instance.CacheSceneObject();
+
             // 通知等待场景切换的协程
             EventSystem.Instance.Publish<EventType.SceneLoadFinish>();
             scene.GetComponent<ObjectWait>().Notify(new Wait_SceneChangeFinish());

+ 10 - 2
Unity/Assets/Scripts/Codes/HotfixView/Client/Unit/OnDestroyZoneObject.cs

@@ -7,14 +7,22 @@ namespace ET.Client
     {
         protected override async ETTask Run(Scene scene, EventType.OnDestroyZoneObject args)
         {
-            Log.Debug($"remove unit view: {args.ObjectId}");
+            //Log.Debug($"remove unit view: {args.ObjectId}");
             DestroyUnitModel(args.ObjectId);
             await ETTask.CompletedTask;
         }
 
         private void DestroyUnitModel(uint unitid)
         {
-            ModelViewComponent.Instance?.RemoveChild(unitid);
+            if(ModelViewComponent.Instance != null && GameObjectPool.Instance != null)
+            {
+                var render = ModelViewComponent.Instance.GetChild<UnitRenderComponet>(unitid);
+                if(render != null)
+                {
+                    GameObjectPool.Instance.RecycleObject(render.GameObject);
+                }
+                ModelViewComponent.Instance.RemoveChild(unitid);
+            }
 
             if (unitid == UnitMgr.Instance.ActorId)
             {

+ 14 - 15
Unity/Assets/Scripts/Codes/HotfixView/Client/Unit/OnNewZoneObject.cs

@@ -1,6 +1,5 @@
 using CommonAI.ZoneClient;
 using Sirenix.Utilities;
-using System.Text.RegularExpressions;
 using UnityEngine;
 
 namespace ET.Client
@@ -30,23 +29,21 @@ namespace ET.Client
         private async ETTask CreatUnitModel(BattleUnit unit)
         {
             var zu = unit.ZUnit;
-            
-            var handle = await YooAssetProxy.LoadAssetAsync<GameObject>($"Unit_{zu.Info.FileName}");
-            if(!UnitMgr.Instance.HasUnit(zu.ObjectID))
+            var go = await GameObjectPool.Instance.Acquire($"Unit_{zu.Info.FileName}");
+            go.SetActive(true);
+            if (!UnitMgr.Instance.HasUnit(zu.ObjectID))
             {
                 //还没显示就已挂掉的单位,走好
                 Log.Debug($"ignore dead unit: {zu}@{zu.ObjectID}");
                 return;
             }
+            ModelViewComponent.Instance.AddChildWithId<UnitRenderComponet, GameObject>(unit.Id, go, true);
 
-            var prefab = handle.GetAssetObject<GameObject>();
-            GameObject go = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.Unit, true);
+            go.transform.parent = GlobalViewComponent.Instance.Unit;
             vecTemp.Set(zu.X, zu.Y, zu.Z);
             go.transform.position = RenderUtils.UnityPosFromBattle(vecTemp);
             go.transform.rotation = RenderUtils.UnityRotationFromBattle(zu.Direction);
 
-            ModelViewComponent.Instance.AddChildWithId<UnitRenderComponet, GameObject>(unit.Id, go, true);
-
             if (unit is BattleActor)
             {
                 CameraMgr.FollowMe(go.transform.position);
@@ -59,9 +56,13 @@ namespace ET.Client
         private async ETTask CreateSpellModel(BattleSpell spell)
         {
             var zs = spell.ZoneObject as ZoneSpell;
-            //spell effect hack
             var res = zs.Info.FileName;
-            var handle = await YooAssetProxy.LoadAssetAsync<GameObject>($"Effect_{res}");
+            if(res.IsNullOrWhitespace())
+            {
+                Log.Debug($"spell({zs.Info.ID}) not config fileName");
+                return;
+            }
+
             if (!UnitMgr.Instance.HasUnit(zs.ObjectID) || (zs.Sender != null && !UnitMgr.Instance.HasUnit(zs.Sender.ObjectID)))
             {
                 //还没显示就已挂掉的单位,走好
@@ -69,15 +70,13 @@ namespace ET.Client
                 return;
             }
 
-            var prefab = handle.GetAssetObject<GameObject>();
-            GameObject go = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.Unit, true);
-            vecTemp.Set(zs.X, zs.Y, zs.Z);
-            go.name = "spell_" + zs.ObjectID;
+            GameObject go = await GameObjectPool.Instance.Acquire($"Effect_{res}");
+            go.SetActive(true);
             go.transform.localScale = Vector3.one * zs.Info.FileBodyScale;
+            vecTemp.Set(zs.X, zs.Y, zs.Z);
             go.transform.position = RenderUtils.UnityPosFromBattle(vecTemp);
             go.transform.rotation = RenderUtils.UnityRotationFromBattle(zs.Direction);
             ModelViewComponent.Instance.AddChildWithId<UnitRenderComponet, GameObject>(zs.ObjectID, go, true);
-            Log.Debug($"spellRender({zs.ObjectID}) ok.");
         }
     }
 }

+ 5 - 0
Unity/Assets/Scripts/Codes/HotfixView/Client/Unit/UnitRenderSystem.cs

@@ -153,6 +153,7 @@ namespace ET.Client
         //执行指令
         private static void ExeCommand(this UnitRenderComponet self, AnimatorCommand cmd)
         {
+            Log.Debug($"{self.GameObject.name} play ani:{cmd.Type}");
             self.DoingCmd = (AnimatorCommand)cmd;
             self.AniData.PlayAnimation(cmd.Type);
         }
@@ -199,6 +200,10 @@ namespace ET.Client
                 {
                     cmds.RemoveRange(0, delIndex + 1);
                 }
+                else
+                {
+                    cmds.Clear();
+                }
             }
             else
             {

+ 22 - 0
Unity/Assets/Scripts/Codes/ModelView/Client/Unit/ModelViewComponent.cs

@@ -9,4 +9,26 @@ namespace ET.Client
         [StaticField]
         public static ModelViewComponent Instance;
     }
+
+    [FriendOf(typeof(ModelViewComponent))]
+    public static class ModelViewComponentSystem
+    {
+        [ObjectSystem]
+        public class ModelViewComponentAwakeSystem : AwakeSystem<ModelViewComponent>
+        {
+            protected override void Awake(ModelViewComponent self)
+            {
+                ModelViewComponent.Instance = self;
+            }
+        }
+
+        [ObjectSystem]
+        public class ModelViewComponentDestroySystem : DestroySystem<ModelViewComponent>
+        {
+            protected override void Destroy(ModelViewComponent self)
+            {
+                ModelViewComponent.Instance = null;
+            }
+        }
+    }
 }

+ 1 - 0
Unity/Assets/Scripts/Codes/Mono/AnimationData.cs

@@ -50,6 +50,7 @@ namespace Mono
             var clip = GetClip(type);
             if (clip != null)
             {
+                //Log.Debug($"Play ani:{type}");
                 var state = Animancer.Play(clip);
                 state.Time = 0;
                 if(endcb != null)