using CommonAI.Zone; using CommonAI.Zone.ZoneEditor; using CommonLang; using FairyGUI; using Sirenix.Utilities; using System; using System.Collections.Generic; using System.Text.RegularExpressions; using UnityEngine; namespace ET.Client { [FriendOf(typeof(GameObjectPool))] public static class GameObjectPoolSystem { [ObjectSystem] public class GameObjectPoolAwakeSystem : AwakeSystem { protected override void Awake(GameObjectPool self) { GameObjectPool.Instance = self; } } [ObjectSystem] public class GameObjectPoolDestroySystem : DestroySystem { 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> goPool = new(); private readonly HashMap audioPool = new(); private readonly ListheadBarPool = new(); public async ETTask CachePrefab(string name) { var handle = await YooAssetProxy.LoadAssetAsync(name); var prefab = handle.GetAssetObject(); var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.RecycleNode, true); gameobj.name = name; RecycleObject(gameobj); } //TODO: 选取当前场景的单位、技能(事件触发等等) //TODO: BUFF public async ETTask CacheSceneObject(int scnId) { var mgr = BattleResourceMgr.Instance.GameEditorTemplates; var templates = mgr.Templates; SceneData sceneData = mgr.LoadScene(scnId, false, true); BattleMgr.Instance.Layer.Data = sceneData; List effectlist = new(); List soundlist = new(); if(!sceneData.BGM.IsNullOrWhitespace()) { soundlist.Add(sceneData.BGM); } //遍历模型 var units = templates.getUnits(); foreach(var unit in units.Values) { await CachePrefab($"Unit_{unit.FileName}"); if(unit.FootCircleEffect != null) CacheLaunchEffect(unit.FootCircleEffect, ref effectlist, ref soundlist); if (unit.SpawnEffect != null) CacheLaunchEffect(unit.SpawnEffect, ref effectlist, ref soundlist); if (unit.DeadAnimationEndEffect != null) CacheLaunchEffect(unit.DeadAnimationEndEffect, ref effectlist, ref soundlist); if (unit.DeadEffect != null) CacheLaunchEffect(unit.DeadEffect, ref effectlist, ref soundlist); if (unit.HitBreakEffect != null) CacheLaunchEffect(unit.HitBreakEffect, ref effectlist, ref soundlist); if (unit.ChangeForceEffect != null) CacheLaunchEffect(unit.ChangeForceEffect, ref effectlist, ref soundlist); if (unit.CrushEffect != null) CacheLaunchEffect(unit.CrushEffect, ref effectlist, ref soundlist); if (unit.DamageEffect != null) CacheLaunchEffect(unit.DamageEffect, ref effectlist, ref soundlist); if (unit.RemovedEffect != null) CacheLaunchEffect(unit.RemovedEffect, ref effectlist, ref soundlist); if (!unit.PreloadResources.IsNullOrWhitespace() ) { var split = unit.PreloadResources.Split(';'); foreach(var res in split) { var realres = res; var cns = res.Split('|'); var cnt = 1; if (cns.Length > 1) { realres = cns[0]; try { cnt = Convert.ToInt32(cns[1]); } catch { Log.Error($"PreloadResources illegal: {unit.PreloadResources}"); break; } } for (var i = 0; i < cnt; i++) { await CachePrefab(realres); } } } } 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) { CacheLaunchEffect(kf.Effect, ref effectlist, ref soundlist); } if (kf.Spell != null) { for (var i = 0; i < kf.Spell.Count; i++) { CacheSpellEffect(templates, kf.Spell.SpellID, ref effectlist, ref soundlist); } } } } } foreach (var ef in effectlist) { await CachePrefab($"Effect_{ef}"); } foreach (var sound in soundlist) { var key = sound; var m = Regex.Match(key, "/?res/sound/.*/([\\w_\\d]+)\\.assetbundles$"); if (m.Success) { key = m.Groups[1].Value.ToLower(); } if (audioPool.ContainsKey(key)) { continue; } //Log.Debug($"cache audio: {key}"); var handle = await YooAssetProxy.LoadAssetAsync($"Sound_{key}"); var ac = handle.GetAssetObject(); ac.LoadAudioData(); audioPool.Add(key, ac); } } private void CacheLaunchEffect(LaunchEffect effect, ref Listeffectlist, ref List soundlist) { if(!effect.Name.IsNullOrWhitespace()) { effectlist.Add(effect.Name); } if(!effect.SoundName.IsNullOrWhitespace()) { soundlist.Add(effect.SoundName); } } private void CacheSpellEffect(TemplateManager templates, int spellid, ref List effectlist, ref List soundlist, int loopbackCheckid = 0) { if(spellid == loopbackCheckid) { Log.Error($"found spell loopback: {loopbackCheckid}"); return; } 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) { CacheLaunchEffect(frame.Effect, ref effectlist, ref soundlist); } if (frame.Spell != null && frame.Spell.SpellID != 0) { CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist, ref soundlist, spellid); } if (frame.Attack != null) { var attack = frame.Attack; if (attack.Effect != null) { CacheLaunchEffect(attack.Effect, ref effectlist, ref soundlist); } if (attack.Spell != null && attack.Spell.SpellID != 0) { CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist, ref soundlist, spellid); } } } frame = spell.HitOnExplosionKeyFrame; if (spell.HitOnExplosion && frame != null) { if (frame.Effect != null) { CacheLaunchEffect(frame.Effect, ref effectlist, ref soundlist); } if (frame.Spell != null && frame.Spell.SpellID != 0) { CacheSpellEffect(templates, frame.Spell.SpellID, ref effectlist, ref soundlist, spellid); } if (frame.Attack != null) { var attack = frame.Attack; if (attack.Effect != null) { CacheLaunchEffect(attack.Effect, ref effectlist, ref soundlist); } if (attack.Spell != null && attack.Spell.SpellID != 0) { CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist, ref soundlist, spellid); } } } foreach (var frm in spell.KeyFrames) { if (frm.Effect != null) { CacheLaunchEffect(frm.Effect, ref effectlist, ref soundlist); } if (frm.Spell != null && frm.Spell.SpellID != 0) { CacheSpellEffect(templates, frm.Spell.SpellID, ref effectlist, ref soundlist, spellid); } if (frm.Attack != null) { var attack = frm.Attack; if (attack.Effect != null) { CacheLaunchEffect(attack.Effect, ref effectlist, ref soundlist); } if (attack.Spell != null && attack.Spell.SpellID != 0) { CacheSpellEffect(templates, attack.Spell.SpellID, ref effectlist, ref soundlist, spellid); } } } } public void ClearCache() { foreach (var list in goPool.Values) { foreach (var go in list) { GameObject.Destroy(go); } } goPool.Clear(); foreach(var ac in audioPool.Values) { ac.UnloadAudioData(); } audioPool.Clear(); } public void RecycleObject(GameObject go, string key = "") { if(key.IsNullOrWhitespace()) { key = go.name; } //Log.Debug($"recycle 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() { go }); } } public async ETTask Acquire(string key) { if (goPool.TryGetValue(key, out var golist)) { if (golist.Count > 0) { var gobj = golist[0]; golist.RemoveRange(0, 1); return gobj; } } else { goPool.Add(key, new List()); } Log.Warning($"not cache gameobject: ({key})"); var handle = await YooAssetProxy.LoadAssetAsync(key); var prefab = handle.GetAssetObject(); var gameobj = UnityEngine.Object.Instantiate(prefab, GlobalViewComponent.Instance.RecycleNode, true); gameobj.name = key; return gameobj; } public async ETTask AcquireSound(string key) { if(audioPool.TryGetValue(key, out var ac)) { return ac; } Log.Warning($"not cache audio: ({key})"); var handle = await YooAssetProxy.LoadAssetAsync($"Sound_{key}"); var aac = handle.GetAssetObject(); aac.LoadAudioData(); audioPool.Add(key, aac); return aac; } public async ETTask AcquireHeadBar() { if(headBarPool.Count > 0) { var ret = headBarPool[0]; headBarPool.RemoveAt(0); return ret; } var root = GlobalViewComponent.Instance.HeadbarView; if (root == null) { //加入所有headbar的parent view root = await UIHelper.Create("HeadBar", "HeadBarRoot", 0); GlobalViewComponent.Instance.HeadbarView = root; root.visible = false; } var view = await UIHelper.Create("HeadBar", "normalbar", -1, root); return view; } public void RecycleHeadBar(GComponent view) { headBarPool.Add(view); } } }