using System.Collections; using System.Collections.Generic; using UnityEngine; using XLua; namespace Coolape { public class InvokeEx : MonoBehaviour { public bool canFixedUpdate = false; public bool canUpdate = false; public static InvokeEx self; public InvokeEx () { self = this; } Hashtable coroutineMap = Hashtable.Synchronized (new Hashtable ()); Hashtable coroutineIndex = Hashtable.Synchronized (new Hashtable ()); /// /// Invoke4s the lua.回调lua函数, 等待时间 /// /// only support Luafunction or Callback /// Callbak func. /// /// /// Sec. /// public static UnityEngine.Coroutine invoke (object callbakFunc, float sec) { return self.invoke4Lua (callbakFunc, sec); } public static UnityEngine.Coroutine invoke (object callbakFunc, object orgs, float sec) { return self.invoke4Lua (callbakFunc, orgs, sec); } public static UnityEngine.Coroutine invoke (object callbakFunc, object orgs, float sec, bool onlyOneCoroutine) { return self.invoke4Lua (callbakFunc, orgs, sec, onlyOneCoroutine); } public UnityEngine.Coroutine invoke4Lua (object callbakFunc, float sec) { return invoke4Lua (callbakFunc, "", sec); } public UnityEngine.Coroutine invoke4Lua (object callbakFunc, object orgs, float sec) { return invoke4Lua (callbakFunc, orgs, sec, false); } /// /// Invoke4s the lua. /// /// Callbak func.lua函数 /// Orgs.参数 /// Sec.等待时间 public UnityEngine.Coroutine invoke4Lua (object callbakFunc, object orgs, float sec, bool onlyOneCoroutine) { if (!gameObject.activeInHierarchy) return null; if (callbakFunc == null) { Debug.LogError ("callbakFunc is null ......"); return null; } try { UnityEngine.Coroutine ct = null; if (onlyOneCoroutine) { cleanCoroutines (callbakFunc); } int index = getCoroutineIndex (callbakFunc); ct = StartCoroutine (doInvoke4Lua (callbakFunc, sec, orgs, index)); setCoroutine (callbakFunc, ct, index); return ct; } catch (System.Exception e) { Debug.LogError (callbakFunc + ":" + e); return null; } } public int getCoroutineIndex (object callbakFunc) { object key = getKey4InvokeMap (callbakFunc, coroutineIndex); int ret = MapEx.getInt (coroutineIndex, key); coroutineIndex [key] = ret + 1; return ret; } public void setCoroutineIndex (object callbakFunc, int val) { object key = getKey4InvokeMap (callbakFunc, coroutineIndex); coroutineIndex [key] = val; } /// /// Gets the key4 invoke map.当直接传luafunction时,不能直接用,用Equals查找一下key /// /// The key4 invoke map. /// Callbak func. /// Map. public object getKey4InvokeMap (object callbakFunc, Hashtable map) { if (callbakFunc == null || map == null) return callbakFunc; object key = callbakFunc; if (callbakFunc != null) { NewList keys = ObjPool.listPool.borrowObject (); keys.AddRange (map.Keys); for (int i = 0; i < keys.Count; i++) { if ((callbakFunc).Equals ((keys [i]))) { key = keys [i]; break; } } ObjPool.listPool.returnObject (keys); keys = null; } return key; } public Hashtable getCoroutines (object callbakFunc) { object key = getKey4InvokeMap (callbakFunc, coroutineMap); Hashtable ret = MapEx.getMap(coroutineMap, key); ret = ret == null ? new Hashtable() : ret; coroutineMap[key] = ret; return ret; } public void setCoroutine (object callbakFunc, UnityEngine.Coroutine ct, int index) { object key = getKey4InvokeMap (callbakFunc, coroutineMap); Hashtable map = getCoroutines (callbakFunc); map [index] = ct; coroutineMap [key] = map; } public void cleanCoroutines (object callbakFunc) { object key = getKey4InvokeMap (callbakFunc, coroutineMap); Hashtable list = getCoroutines (callbakFunc); foreach (DictionaryEntry cell in list) { StopCoroutine ((UnityEngine.Coroutine)(cell.Value)); } list.Clear (); setCoroutineIndex (callbakFunc, 0); coroutineMap.Remove (key); } public void rmCoroutine (object callbakFunc, int index) { object key = getKey4InvokeMap (callbakFunc, coroutineMap); Hashtable list = getCoroutines (callbakFunc); list.Remove (index); coroutineMap [key] = list; } public static void cancelInvoke () { self.cancelInvoke4Lua (); } public static void cancelInvoke (object callbakFunc) { self.cancelInvoke4Lua (callbakFunc); } public void cancelInvoke4Lua () { cancelInvoke4Lua (null); } public void cancelInvoke4Lua (object callbakFunc) { if (callbakFunc == null) { Hashtable list = null; NewList keys = ObjPool.listPool.borrowObject(); keys.AddRange(coroutineMap.Keys); object key = null; for (int i = 0; i < keys.Count; i++) { key = keys[i]; if (key != null) { list = getCoroutines(key); foreach (DictionaryEntry cell in list) { StopCoroutine((UnityEngine.Coroutine)(cell.Value)); } list.Clear(); } } coroutineMap.Clear (); coroutineIndex.Clear (); ObjPool.listPool.returnObject(keys); } else { cleanCoroutines (callbakFunc); } } Queue invokeFuncs = new Queue (); IEnumerator doInvoke4Lua (object callbakFunc, float sec, object orgs, int index) { yield return new WaitForSeconds (sec); try { rmCoroutine (callbakFunc, index); Utl.doCallback (callbakFunc, orgs); } catch (System.Exception e) { string msg = "call err:doInvoke4Lua" + ",callbakFunc=[" + callbakFunc + "]"; Debug.LogError (msg); Debug.LogError (e); } } //================================================ // Fixed invoke 4 lua //================================================ long _frameCounter = 0; object locker=new object(); public long frameCounter { get { lock (locker) { return _frameCounter; } } set { lock (locker) { _frameCounter = value; } } } Hashtable _fixedInvokeMap = new Hashtable (); public Hashtable fixedInvokeMap { get { if (_fixedInvokeMap == null) { _fixedInvokeMap = Hashtable.Synchronized (new Hashtable ()); } return _fixedInvokeMap; } } public static void invokeByFixedUpdate (object luaFunc, float waitSec) { if (self == null) { Debug.LogError ("Must attach InvokeEx on some gameObject!"); return; } self._fixedInvoke (luaFunc, null, waitSec); } public static void invokeByFixedUpdate (object luaFunc, object paras, float waitSec) { if (self == null) { Debug.LogError ("Must attach InvokeEx on some gameObject!"); return; } self._fixedInvoke (luaFunc, paras, waitSec); } public void fixedInvoke4Lua (object luaFunc, float waitSec) { _fixedInvoke (luaFunc, null, waitSec); } public void fixedInvoke4Lua (object luaFunc, object paras, float waitSec) { _fixedInvoke (luaFunc, paras, waitSec); } void _fixedInvoke (object callback, object paras, float waitSec) { int waiteFrame = Mathf.CeilToInt (waitSec / Time.fixedDeltaTime); waiteFrame = waiteFrame <= 0 ? 1 : waiteFrame; //至少有帧 long key = frameCounter + waiteFrame; object[] content = new object[2]; // print (waiteFrame + "===" + key +"====" + luaFunc); List funcList = (List)(fixedInvokeMap [key]); if (funcList == null) { funcList = new List (); } content [0] = callback; content [1] = paras; funcList.Add (content); fixedInvokeMap [key] = funcList; if(!canFixedUpdate) { canFixedUpdate = true; } } public static void cancelInvokeByFixedUpdate () { cancelInvokeByFixedUpdate (null); } public static void cancelInvokeByFixedUpdate (object func) { self.cancelFixedInvoke4Lua (func); } public void cancelFixedInvoke4Lua () { cancelFixedInvoke4Lua (null); } public void cancelFixedInvoke4Lua (object func) { if (func == null) { if (fixedInvokeMap != null) { fixedInvokeMap.Clear (); } return; } List list = null; int count = 0; object[] content = null; foreach (DictionaryEntry item in fixedInvokeMap) { list = (List)(item.Value); count = list.Count; for (int i = count - 1; i >= 0; i--) { content = list [i]; if (func.Equals (content [0])) { list.RemoveAt (i); } } if(list.Count == 0) { fixedInvokeMap.Remove (item); } } } void doFixedInvoke (long key) { if (fixedInvokeMap == null && fixedInvokeMap.Count <= 0) return; if (fixedInvokeMap [key] == null) return; object[] content = null; List funcList = (List)(fixedInvokeMap [key]); object callback = null; if (funcList != null) { for (int i = 0; i < funcList.Count; i++) { content = funcList [i]; callback = content [0]; Utl.doCallback (callback, content [1]); } funcList.Clear (); funcList = null; fixedInvokeMap.Remove (key); } } //================================================ // FixedUpdate //================================================ //帧统计 public virtual void FixedUpdate () { if (!canFixedUpdate) return; frameCounter++; if (fixedInvokeMap != null && fixedInvokeMap.Count > 0) { doFixedInvoke (frameCounter); } else { canFixedUpdate = false; frameCounter = 0; } } //================================================ // Update //================================================ ArrayList _invokeByUpdateList = null; ArrayList invokeByUpdateList { get { if (_invokeByUpdateList == null) { _invokeByUpdateList = ArrayList.Synchronized (new ArrayList ()); } return _invokeByUpdateList; } } /// /// Invoke4s the lua. /// /// Callbak func.lua函数 /// Orgs.参数 /// Sec.等待时间 public static void invokeByUpdate (object callbakFunc, float sec) { self.updateInvoke (callbakFunc, sec); } public static void invokeByUpdate (object callbakFunc, object orgs, float sec) { self.updateInvoke (callbakFunc, orgs, sec); } public void updateInvoke (object callbakFunc, float sec) { updateInvoke (callbakFunc, null, sec); } public void updateInvoke (object callbakFunc, object orgs, float sec) { if (callbakFunc == null) return; NewList list = ObjPool.listPool.borrowObject (); list.Add (callbakFunc); list.Add (orgs); list.Add (Time.unscaledTime + sec); invokeByUpdateList.Add (list); canUpdate = true; } public static void cancelInvokeByUpdate () { self.cancelUpdateInvoke (); } public static void cancelInvokeByUpdate (object callbakFunc) { self.cancelUpdateInvoke (callbakFunc); } public void cancelUpdateInvoke () { cancelUpdateInvoke (null); } public void cancelUpdateInvoke (object callbakFunc) { NewList list = null; int count = invokeByUpdateList.Count; if (callbakFunc == null) { for (int i = 0; i < count; i++) { list = (NewList)(invokeByUpdateList [i]); ObjPool.listPool.returnObject (list); } list = null; invokeByUpdateList.Clear (); return; } for (int i = count - 1; i >= 0; i--) { list = (NewList)(invokeByUpdateList [i]); if (callbakFunc.Equals (list [0])) { invokeByUpdateList.RemoveAt (i); ObjPool.listPool.returnObject (list); } } list = null; } void doInvokeByUpdate () { int count = invokeByUpdateList.Count; NewList list = null; object callbakFunc; object orgs; float sec; int index = 0; while (index < invokeByUpdateList.Count) { list = (NewList)(invokeByUpdateList [index]); callbakFunc = list [0]; orgs = list [1]; sec = (float)(list [2]); if (sec <= Time.unscaledTime) { invokeByUpdateList.RemoveAt(index); Utl.doCallback (callbakFunc, orgs); ObjPool.listPool.returnObject (list); } else { index++; } } list = null; } public virtual void Update () { if (!canUpdate) return; if (invokeByUpdateList.Count > 0) { doInvokeByUpdate (); } else { canUpdate = false; } } } }