From 818bd8eafdb7fb438b0424312e1a060733b1963e Mon Sep 17 00:00:00 2001 From: ALEXTANG <574809918@qq.com> Date: Mon, 19 Sep 2022 17:44:41 +0800 Subject: [PATCH] ACSystem ACSystem --- Assets/TEngine/Scripts/Runtime/Actor.meta | 3 + .../Scripts/Runtime/Actor/ActorComponent.meta | 3 + .../Actor/ActorComponent/ActorAttribute.cs | 128 ++++ .../ActorComponent/ActorAttribute.cs.meta | 3 + .../Actor/ActorComponent/ActorComponent.cs | 301 ++++++++++ .../ActorComponent/ActorComponent.cs.meta | 3 + .../ActorComponent/ActorComponentPool.cs | 148 +++++ .../ActorComponent/ActorComponentPool.cs.meta | 3 + .../ActorComponent/ActorDebugerBehaviour.cs | 90 +++ .../ActorDebugerBehaviour.cs.meta | 3 + .../ActorComponent/ActorEventDispatcher.cs | 447 ++++++++++++++ .../ActorEventDispatcher.cs.meta | 3 + .../Actor/ActorComponent/ActorEventHelper.cs | 30 + .../ActorComponent/ActorEventHelper.cs.meta | 3 + .../Actor/ActorComponent/ActorEventType.cs | 7 + .../ActorComponent/ActorEventType.cs.meta | 3 + .../Scripts/Runtime/Actor/ActorManager.cs | 248 ++++++++ .../Runtime/Actor/ActorManager.cs.meta | 3 + .../Scripts/Runtime/Actor/ActorTimerMgr.cs | 554 ++++++++++++++++++ .../Runtime/Actor/ActorTimerMgr.cs.meta | 3 + .../Scripts/Runtime/Actor/GameActor.cs | 277 +++++++++ .../Scripts/Runtime/Actor/GameActor.cs.meta | 3 + .../Scripts/Runtime/Actor/GameActorExt.cs | 120 ++++ .../Runtime/Actor/GameActorExt.cs.meta | 3 + 24 files changed, 2389 insertions(+) create mode 100644 Assets/TEngine/Scripts/Runtime/Actor.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs.meta create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs create mode 100644 Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs.meta diff --git a/Assets/TEngine/Scripts/Runtime/Actor.meta b/Assets/TEngine/Scripts/Runtime/Actor.meta new file mode 100644 index 00000000..8075d03c --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 334a6fb5ca0d4c62b3f3fdf9b32d37ab +timeCreated: 1663555394 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent.meta new file mode 100644 index 00000000..903b317f --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6731a6b3e0ce4882b9ef2c5a890684ea +timeCreated: 1663559772 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs new file mode 100644 index 00000000..f6d87c8b --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; + +namespace TEngine.Runtime.Actor +{ + public class ActorAttribute + { + private class AttrChangeHandler + { + public Delegate Handle; + + public void AddDelegate(Delegate handler) + { + Handle = Delegate.Combine(Handle, handler); + } + + public void RmvDelegate(Delegate handler) + { + Handle = Delegate.Remove(Handle, handler); + } + } + + private readonly Dictionary _dictAttr = new Dictionary(); + private readonly Dictionary _attrChangedListener = new Dictionary(); + + public void ClearAttribute(int attrId) + { + _dictAttr.Remove((int)attrId); + } + + public void SetAttribute(int attrId, T val) + { + bool changed = false; + + T existVal; + object exist; + if (_dictAttr.TryGetValue(attrId, out exist)) + { + existVal = (T)exist; + + if (!EqualityComparer.Default.Equals(existVal, val)) + { + changed = true; + } + } + else + { + existVal = default(T); + changed = true; + } + + + if (changed) + { + _dictAttr[attrId] = val; + + AttrChangeHandler handler; + if (_attrChangedListener.TryGetValue(attrId, out handler)) + { + Action deleHandle = handler.Handle as Action; + if (deleHandle != null) + { + deleHandle(existVal, val); + } + } + } + } + + public T GetAttribute(int attrId) + { + T val; + TryGetAttribute(attrId, out val); + return val; + } + + public bool IsHaveAttribute(int attrId) + { + return _dictAttr.ContainsKey((int)attrId); + } + + public bool TryGetAttribute(int attrId, out T val) + { + return GetAttributeValue((int)attrId, out val); + } + + public bool GetAttributeValue(int attrId, out T val) + { + object objVal; + var ret = _dictAttr.TryGetValue(attrId, out objVal); + if (ret) + { + val = (T)objVal; + } + else + { + val = default(T); + } + + return ret; + } + + public void RegAttrChangeEvent(int attrId, Action handler) + { + AttrChangeHandler handleNode; + if (!_attrChangedListener.TryGetValue(attrId, out handleNode)) + { + handleNode = new AttrChangeHandler(); + _attrChangedListener[attrId] = handleNode; + } + + handleNode.AddDelegate(handler); + } + + public void UnRegAttrChangeEvent(int attrId, Action handler) + { + UnRegAttrChangeEvent(attrId, handler); + } + + public void UnRegAttrChangeEvent(int attrId, Delegate handler) + { + AttrChangeHandler handleNode; + if (_attrChangedListener.TryGetValue(attrId, out handleNode)) + { + handleNode.RmvDelegate(handler); + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs.meta new file mode 100644 index 00000000..e3ede718 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8b72801b116e4865983ba9e6c85a40b3 +timeCreated: 1663560140 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs new file mode 100644 index 00000000..aa126dca --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs @@ -0,0 +1,301 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Runtime.Actor +{ + /// + /// Actor 组件基类 + /// + public abstract class ActorComponent + { + public bool m_callStart = false; + private bool m_calledOnDestroy = false; + protected GameActor m_actor; + + private List m_registAttrChanged = new List(); + + public bool m_destroy; + public ActorComponent m_prev; + public ActorComponent m_next; + + public GameTimer m_updateTimer; + public GameTimer m_lateUpdateTimer; + public bool m_needOnceUpdate = false; + public bool m_needLoopUpdate = false; + public bool m_needLoopLateUpdate = false; + + protected void RequestOnceUpdate() + { + if (!m_callStart) + { + m_needOnceUpdate = true; + return; + } + + if (GameTimer.IsNull(m_updateTimer)) + { + ActorComponentPool.Instance.RequestOnceUpdate(this); + } + } + + protected void RequestLoopUpdate(string detail = null) + { + if (!m_callStart) + { + m_needLoopUpdate = true; + return; + } + + if (GameTimer.IsNull(m_updateTimer)) + { + ActorComponentPool.Instance.RequestLoopUpdate(this, detail); + } + } + + protected void RequestLoopLateUpdate() + { + if (!m_callStart) + { + m_needLoopLateUpdate = true; + return; + } + + if (GameTimer.IsNull(m_lateUpdateTimer)) + { + ActorComponentPool.Instance.RequestLoopLateUpdate(this); + } + } + + protected void StopLoopUpdate() + { + ///如果是持久update的类型 + if (!m_callStart) + { + m_needLoopUpdate = false; + return; + } + + if (!GameTimer.IsNull(m_updateTimer)) + { + ActorComponentPool.Instance.StopLoopUpdate(this); + } + } + + private class RegisterAttrChangeData + { + public int AttrId; + public Delegate Handler; + + public RegisterAttrChangeData(int attrId, Delegate handler) + { + AttrId = attrId; + Handler = handler; + } + } + + public GameActor OwnActor + { + get + { + if (m_actor != null && m_actor.IsDestroyed) + { + m_actor = null; + return null; + } + + return m_actor; + } + } + + + public Vector3 Position + { + get { return m_actor.Position; } + } + + #region 扩展接口 + + protected virtual void Awake() + { + } + + protected virtual void Start() + { + } + + public virtual void LateUpdate() + { + } + + public virtual void Update() + { + } + + protected virtual void OnDestroy() + { + } + + /// + /// 不显示的时候是否需要update + /// + /// + public virtual bool IsInvisibleNeedUpdate() + { + return true; + } + + #endregion + + #region 操作接口 + + /// + /// 只有添加到对象上,才触发下面的初始化逻辑 + /// + /// + /// + public bool BeforeAddToActor(GameActor actor) + { + m_actor = actor; + m_callStart = false; + Awake(); + + AddDebug(); + return true; + } + + public void BeforeDestroy() + { + if (m_calledOnDestroy) + { + return; + } + + RmvDebug(); + + m_calledOnDestroy = true; + if (m_actor != null) + { + ClearAllEventChangeHandler(); + OnDestroy(); + } + } + + public void CallStart() + { + Log.Assert(!m_callStart); + Start(); + m_callStart = true; + } + + + public void AfterOnStartAction(ActorTimerMgr timerMgr) + { + if (m_needLoopUpdate) + { + Log.Assert(GameTimer.IsNull(m_updateTimer)); + + timerMgr.CreateLoopFrameTimer(ref m_updateTimer, GetType().FullName, Update); + } + else if (m_needOnceUpdate) + { + Log.Assert(GameTimer.IsNull(m_updateTimer)); + + if (GameTimer.IsNull(m_updateTimer)) + { + m_updateTimer = timerMgr.CreateOnceFrameTimer(GetType().FullName, Update); + } + } + + if (m_needLoopLateUpdate) + { + Log.Assert(GameTimer.IsNull(m_lateUpdateTimer)); + + timerMgr.CreateLoopFrameLateTimer(ref m_lateUpdateTimer, GetType().FullName, LateUpdate); + } + } + + #endregion + + #region DebugBehaviour + + protected void AddDebug() + { +#if UNITY_EDITOR + var debugData = UnityUtil.AddMonoBehaviour(OwnActor.gameObject); + debugData.AddDebugComponent(GetType().Name); +#endif + } + + protected void RmvDebug() + { +#if UNITY_EDITOR + var debugData = UnityUtil.AddMonoBehaviour(OwnActor.gameObject); + debugData.RmvDebugComponent(GetType().Name); +#endif + } + + protected void SetDebugInfo(string key, string val) + { +#if UNITY_EDITOR + var debugData = UnityUtil.AddMonoBehaviour(OwnActor.gameObject); + debugData.SetDebugInfo(GetType().Name, key, val); +#endif + } + + protected void RemoveAllDebugInfo() + { +#if UNITY_EDITOR + var debugData = UnityUtil.AddMonoBehaviour(OwnActor.gameObject); + debugData.RemoveAllDebugInfo(GetType().Name); +#endif + } + + #endregion + + #region EventBehaviour + + public void AddEventListener(int eventId, Action eventCallback) + { + m_actor.Event.AddEventListener(eventId, eventCallback, this); + } + + public void AddEventListener(int eventId, Action eventCallback) + { + m_actor.Event.AddEventListener(eventId, eventCallback, this); + } + + public void AddEventListener(int eventId, Action eventCallback) + { + m_actor.Event.AddEventListener(eventId, eventCallback, this); + } + + public void AddEventListener(int eventId, Action eventCallback) + { + m_actor.Event.AddEventListener(eventId, eventCallback, this); + } + + public void AddEventListener(int eventId, Action eventCallback) + { + m_actor.Event.AddEventListener(eventId, eventCallback, this); + } + + public void RegAttrChangeEvent(int attrId, Action handler) + { + m_registAttrChanged.Add(new RegisterAttrChangeData(attrId, handler)); + OwnActor.Attr.RegAttrChangeEvent((int)attrId, handler); + } + + private void ClearAllEventChangeHandler() + { + var attr = OwnActor.Attr; + for (int i = 0; i < m_registAttrChanged.Count; i++) + { + var data = m_registAttrChanged[i]; + attr.UnRegAttrChangeEvent(data.AttrId, data.Handler); + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs.meta new file mode 100644 index 00000000..bf8b3751 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponent.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11beba8836b148d58a2cd426b79838ae +timeCreated: 1663556055 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs new file mode 100644 index 00000000..8d0803c7 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs @@ -0,0 +1,148 @@ +using TEngine.Runtime; +using UnityEngine; + +namespace TEngine.Runtime.Actor +{ + public class ActorComponentPool: BehaviourSingleton + { + private ActorComponent _listComponentHead; + private ActorComponent _listStartComponentHead; + private ActorTimerMgr _timerMgr; + public override void Awake() + { + _timerMgr = ActorTimerMgr.Instance; + } + + + public T AllocComponent() where T : ActorComponent,new() + { + var component = new T(); + AddToList(ref _listStartComponentHead, component); + + return component; + } + + public void FreeComponent(ActorComponent component) + { + if (component.m_destroy) + { + return; + } + + component.m_destroy = true; + if (!component.m_callStart) + { + RmvFromList(ref _listStartComponentHead, component); + + Debug.Assert(GameTimer.IsNull(component.m_updateTimer)); + Debug.Assert(GameTimer.IsNull(component.m_lateUpdateTimer)); + } + else + { + RmvFromList(ref _listComponentHead, component); + + var timerMgr = _timerMgr; + timerMgr.DestroyTimer(ref component.m_updateTimer); + timerMgr.DestroyTimer(ref component.m_lateUpdateTimer); + } + + Debug.Assert(component.m_next == null && component.m_prev == null); + } + + public override void Update() + { + var timerMgr = _timerMgr; + + while (_listStartComponentHead != null) + { + var start = _listStartComponentHead; + Debug.Assert(!start.m_destroy); + start.CallStart(); + if (start.m_destroy) + { + Debug.Assert(_listStartComponentHead != start); + continue; + } + + RmvFromList(ref _listStartComponentHead, start); + AddToList(ref _listComponentHead, start); + start.AfterOnStartAction(timerMgr); + } + } + + public void RequestOnceUpdate(ActorComponent component) + { + component.m_updateTimer = _timerMgr.CreateOnceFrameTimer(component.GetType().FullName, component.Update); + } + + public void RequestLoopUpdate(ActorComponent component, string detail = null) + { + Debug.Assert(GameTimer.IsNull(component.m_updateTimer)); + var timerName = component.GetType().FullName; + +#if UNITY_EDITOR + if (!string.IsNullOrEmpty(detail)) + { + timerName += ("_" + detail); + } +#endif + + _timerMgr.CreateLoopFrameTimer(ref component.m_updateTimer, timerName, component.Update); + } + + public void StopLoopUpdate(ActorComponent component) + { + _timerMgr.DestroyTimer(ref component.m_updateTimer); + } + + public void RequestLoopLateUpdate(ActorComponent component) + { + Debug.Assert(GameTimer.IsNull(component.m_lateUpdateTimer)); + _timerMgr.CreateLoopFrameLateTimer(ref component.m_lateUpdateTimer, component.GetType().FullName, component.LateUpdate); + } + + public void StopLoopLateUpdate(ActorComponent component) + { + _timerMgr.DestroyTimer(ref component.m_lateUpdateTimer); + } + + private void AddToList(ref ActorComponent head, ActorComponent component) + { + if (head != null) + { + component.m_next = head; + head.m_prev = component; + } + + head = component; + } + + private void RmvFromList(ref ActorComponent head, ActorComponent component) + { + var prev = component.m_prev; + var next = component.m_next; + + if (prev != null) + { + prev.m_next = next; + } + + if (next != null) + { + next.m_prev = prev; + } + + component.m_next = null; + component.m_prev = null; + + if (component == head) + { + head = next; + } + else + { + Debug.Assert(prev != null); + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs.meta new file mode 100644 index 00000000..91feee92 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorComponentPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e484ab8181734897b450b11453a922d5 +timeCreated: 1663557842 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs new file mode 100644 index 00000000..199ade1d --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Runtime.Actor +{ + [Serializable] + public class ActorComponentDebugKeyInfo + { + public string name; + public string val; + } + + [Serializable] + public class ActorComponentDebugInfo + { + public string name; + public List infos = new List(); + } + + /// + /// 用来调试查看actor信息 + /// + public class ActorDebugerBehaviour : MonoBehaviour + { + public List componentInfos = new List(); + + public event Action OnGizmosSelect; + public event Action OnGizmos; + + public ActorComponentDebugInfo AddDebugComponent(string componentName) + { + var componentInfo = componentInfos.Find(item => item.name == componentName); + if (componentInfo == null) + { + componentInfo = new ActorComponentDebugInfo(); + componentInfo.name = componentName; + componentInfos.Add(componentInfo); ; + } + + return componentInfo; + } + + public void RmvDebugComponent(string componentName) + { + componentInfos.RemoveAll((item) => { return item.name == componentName; }); + } + + public void SetDebugInfo(string componentName, string key, string val) + { + var componentInfo = AddDebugComponent(componentName); + var entry = componentInfo.infos.Find(t => t.name == key); + if (entry == null) + { + entry = new ActorComponentDebugKeyInfo(); + entry.name = key; + componentInfo.infos.Add(entry); + } + + entry.val = val; + } + + public void RemoveAllDebugInfo(string cmpName) + { + var cmpInfo = componentInfos.Find((item) => item.name == cmpName); + if (cmpInfo != null) + { + cmpInfo.infos.Clear(); + } + } + +#if UNITY_EDITOR + void OnDrawGizmosSelected() + { + if (OnGizmosSelect!=null) + { + OnGizmosSelect(); + } + } + + void OnDrawGizmos() + { + if (OnGizmos != null) + { + OnGizmos(); + } + } +#endif + } +} diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs.meta new file mode 100644 index 00000000..875b3a84 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorDebugerBehaviour.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0d23fae349f9468c9f7bc6fa9dcb936f +timeCreated: 1663558701 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs new file mode 100644 index 00000000..4f9ec45e --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs @@ -0,0 +1,447 @@ +using System; +using System.Collections.Generic; + +namespace TEngine.Runtime.Actor +{ + public class EventRegInfo + { + public Delegate callback; + public object owner; + public bool deleted; + + public EventRegInfo(Delegate callback, object owner) + { + this.callback = callback; + this.owner = owner; + deleted = false; + } + } + + public class ActorEventDispatcher + { + private readonly Dictionary> _dictAllEventListener = + new Dictionary>(); + + /// + /// 用于标记一个事件是不是正在处理 + /// + private readonly List _processEvent = new List(); + + /// + /// 用于标记一个事件是不是被移除 + /// + private readonly List _delayDeleteEvent = new List(); + + public void DestroyAllEventListener() + { + var itr = _dictAllEventListener.GetEnumerator(); + while (itr.MoveNext()) + { + var kv = itr.Current; + kv.Value.Clear(); + } + + _processEvent.Clear(); + _delayDeleteEvent.Clear(); + itr.Dispose(); + } + + private void AddDelayDelete(int eventId) + { + if (!_delayDeleteEvent.Contains(eventId)) + { + _delayDeleteEvent.Add(eventId); + Log.Info("delay delete eventId[{0}]", eventId); + } + } + + /// + /// 如果找到eventId对应的监听,删除所有标记为delete的监听 + /// + /// + private void CheckDelayDelete(int eventId) + { + if (_delayDeleteEvent.Contains(eventId)) + { + List listListener; + if (_dictAllEventListener.TryGetValue(eventId, out listListener)) + { + for (int i = 0; i < listListener.Count; i++) + { + if (listListener[i].deleted) + { + Log.Info("remove delay delete eventId[{0}]", eventId); + listListener[i] = listListener[listListener.Count - 1]; + listListener.RemoveAt(listListener.Count - 1); + i--; + } + } + } + + _delayDeleteEvent.Remove(eventId); + } + } + + public void SendEvent(int eEventId) + { + int eventId = eEventId; + List listListener; + if (_dictAllEventListener.TryGetValue(eventId, out listListener)) + { + _processEvent.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEvent.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.deleted) + { + continue; + } + + Action callBack = listListener[i].callback as Action; + if (callBack != null) + { + callBack(); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEvent.Count); + Log.Assert(eventId == _processEvent[_processEvent.Count - 1]); +#endif + _processEvent.RemoveAt(_processEvent.Count - 1); + + CheckDelayDelete(eventId); + } + } + + public void SendEvent(int eEventId, T data) + { + int eventId = (int)eEventId; + List listListener; + if (_dictAllEventListener.TryGetValue(eventId, out listListener)) + { + _processEvent.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEvent.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.deleted) + { + continue; + } + + Action callBack = listListener[i].callback as Action; + if (callBack != null) + { + callBack(data); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEvent.Count); + Log.Assert(eventId == _processEvent[_processEvent.Count - 1]); +#endif + + _processEvent.RemoveAt(_processEvent.Count - 1); + + CheckDelayDelete(eventId); + } + } + + public void SendEvent(int eEventId, T dataT, U dataU) + { + int eventId = (int)eEventId; + List listListener; + if (_dictAllEventListener.TryGetValue(eventId, out listListener)) + { + _processEvent.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEvent.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.deleted) + { + continue; + } + + Action callBack = listListener[i].callback as Action; + if (callBack != null) + { + callBack(dataT, dataU); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEvent.Count); + Log.Assert(eventId == _processEvent[_processEvent.Count - 1]); +#endif + _processEvent.RemoveAt(_processEvent.Count - 1); + + CheckDelayDelete(eventId); + } + } + + public void SendEvent(int eEventId, T dataT, U dataU, V dataV) + { + int eventId = (int)eEventId; + List listListener; + if (_dictAllEventListener.TryGetValue(eventId, out listListener)) + { + _processEvent.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEvent.Count; +#endif + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.deleted) + { + continue; + } + + Action callBack = node.callback as Action; + if (callBack != null) + { + callBack(dataT, dataU, dataV); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEvent.Count); + Log.Assert(eventId == _processEvent[_processEvent.Count - 1]); +#endif + _processEvent.RemoveAt(_processEvent.Count - 1); + + CheckDelayDelete(eventId); + } + } + + public void SendEvent(int eEventId, T dataT, U dataU, V dataV, S dataS) + { + int eventId = (int)eEventId; + + List listListener; + if (_dictAllEventListener.TryGetValue(eventId, out listListener)) + { + _processEvent.Add(eventId); +#if UNITY_EDITOR + int iEventCnt = _processEvent.Count; +#endif + + + var count = listListener.Count; + for (int i = 0; i < count; i++) + { + var node = listListener[i]; + if (node.deleted) + { + continue; + } + + Action callBack = listListener[i].callback as Action; + if (callBack != null) + { + callBack(dataT, dataU, dataV, dataS); + } + else + { + Log.Fatal("Invalid event data type: {0}", eventId); + } + } + + +#if UNITY_EDITOR + Log.Assert(iEventCnt == _processEvent.Count); + Log.Assert(eventId == _processEvent[_processEvent.Count - 1]); +#endif + _processEvent.RemoveAt(_processEvent.Count - 1); + + CheckDelayDelete(eventId); + } + } + + public void AddEventListener(int eventHashId, Action eventCallback, object owner) + { + AddEventListenerImp(eventHashId, eventCallback, owner); + } + + public void AddEventListener(int eventHashId, Action eventCallback, object owner) + { + AddEventListenerImp(eventHashId, eventCallback, owner); + } + + public void AddEventListener(int eventHashId, Action eventCallback, object owner) + { + AddEventListenerImp(eventHashId, eventCallback, owner); + } + + public void AddEventListener(int eventHashId, Action eventCallback, object owner) + { + AddEventListenerImp(eventHashId, eventCallback, owner); + } + + public void AddEventListener(int eventHashId, Action eventCallback, + object owner) + { + AddEventListenerImp(eventHashId, eventCallback, owner); + } + + private void AddEventListenerImp(int eventHashId, Delegate listener, object owner) + { + List listListener; + if (!_dictAllEventListener.TryGetValue((int)eventHashId, out listListener)) + { + listListener = new List(); + _dictAllEventListener.Add((int)eventHashId, listListener); + } + + var existNode = listListener.Find((node) => { return node.callback == listener; }); + if (existNode != null) + { + if (existNode.deleted) + { + existNode.deleted = false; + Log.Warning("AddEvent hashId deleted, repeat add: {0}", eventHashId); + return; + } + + Log.Fatal("AddEvent hashId repeated: {0}", eventHashId); + return; + } + + listListener.Add(new EventRegInfo(listener, owner)); + } + + public void RemoveAllListenerByOwner(object owner) + { + var itr = _dictAllEventListener.GetEnumerator(); + while (itr.MoveNext()) + { + var kv = itr.Current; + var list = kv.Value; + + int eventId = kv.Key; + bool isProcessing = _processEvent.Contains(eventId); + bool delayDeleted = false; + + for (int i = 0; i < list.Count; i++) + { + var regInfo = list[i]; + if (regInfo.owner == owner) + { + if (isProcessing) + { + regInfo.deleted = true; + delayDeleted = true; + } + else + { + list[i] = list[list.Count - 1]; + list.RemoveAt(list.Count - 1); + i--; + } + } + } + + if (delayDeleted) + { + AddDelayDelete(eventId); + } + } + + itr.Dispose(); + } + + public void RemoveEventListener(int eventHashId, Action eventCallback) + { + RemoveEventListenerImp(eventHashId, eventCallback); + } + + public void RemoveEventListener(int eventHashId, Action eventCallback) + { + RemoveEventListenerImp(eventHashId, eventCallback); + } + + public void RemoveEventListener(int eventHashId, Action eventCallback) + { + RemoveEventListenerImp(eventHashId, eventCallback); + } + + public void RemoveEventListener(int eventHashId, Action eventCallback) + { + RemoveEventListenerImp(eventHashId, eventCallback); + } + + public void RemoveEventListener(int eventHashId, Action eventCallback) + { + RemoveEventListenerImp(eventHashId, eventCallback); + } + + /// + /// 删除监听,如果是正在处理的监听则标记为删除 + /// + /// + /// + protected void RemoveEventListenerImp(int eventHashId, Delegate listener) + { + List listListener; + if (_dictAllEventListener.TryGetValue(eventHashId, out listListener)) + { + bool isProcessing = _processEvent.Contains(eventHashId); + if (!isProcessing) + { + listListener.RemoveAll((node) => { return node.callback == listener; }); + } + else + { + int listenCnt = listListener.Count; + for (int i = 0; i < listenCnt; i++) + { + var node = listListener[i]; + if (node.callback == listener) + { + node.deleted = true; + AddDelayDelete(eventHashId); + break; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs.meta new file mode 100644 index 00000000..92655a1d --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventDispatcher.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 11f79102b8ab47d28744cb9f8d5ed7cf +timeCreated: 1663559200 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs new file mode 100644 index 00000000..ecef76d5 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs @@ -0,0 +1,30 @@ +namespace TEngine.Runtime.Actor +{ + public static class ActorEventHelper + { + public static void Send(GameActor actor, int eventId) + { + actor.Event.SendEvent(eventId); + } + + public static void Send(GameActor actor, int eventId, T info) + { + actor.Event.SendEvent(eventId, info); + } + + public static void Send(GameActor actor, int eventId, T info1, TU info2) + { + actor.Event.SendEvent(eventId, info1, info2); + } + + public static void Send(GameActor actor, int eventId, T info1, TU info2, TV info3) + { + actor.Event.SendEvent(eventId, info1, info2, info3); + } + + public static void Send(GameActor actor, int eventId, T info1, TU info2, TV info3, TW info4) + { + actor.Event.SendEvent(eventId, info1, info2, info3, info4); + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs.meta new file mode 100644 index 00000000..d21f191f --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9e4e381f3f7a4bb285528fcfd817c120 +timeCreated: 1663559682 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs new file mode 100644 index 00000000..d4a25ac8 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs @@ -0,0 +1,7 @@ +namespace TEngine.Runtime.Actor +{ + public partial class ActorEventType + { + public static int ModelVisibleChange = StringId.StringToHash("ActorEventType.ModelVisibleChange"); + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs.meta new file mode 100644 index 00000000..6d99a3f4 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorComponent/ActorEventType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b6a1564342d24e42974aef898d38228e +timeCreated: 1663577274 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs new file mode 100644 index 00000000..2c6afe90 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs @@ -0,0 +1,248 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Runtime.Actor +{ + public partial class ActorType + { + public static int ActorNone = 1 << 0; + public static int ActorPlayer = 1 << 1; + } + + public delegate bool CheckActorDelegate(GameActor actor); + + public partial class ActorManager : BehaviourSingleton + { + private const uint ClientGidStart = 1000000000; + private const uint ClientGidEnd = 2000000000; + private uint _clientGid = ClientGidStart; + + private Dictionary _actorPool = new Dictionary(); + private Dictionary _goModelHash2Actor = new Dictionary(); + private List _listActor = new List(); + private GameActor _mainPlayer = null; + private int _tickRefreshVisible; + private Dictionary _actorTypes = new Dictionary(); + public Transform ActorRootTrans { get; set; } + + /// + /// 注册Actor类型便于创建 + /// + /// + /// + public void RegisterActorTypes(int actorType,System.Type type) + { + if (!_actorTypes.ContainsKey(actorType)) + { + _actorTypes.Add(actorType,type); + } + } + + public override void Awake() + { + InitActorRoot(); + + _tickRefreshVisible = TimerMgr.Instance.AddTimer(o => { RefreshActorVisible(); }, 1f, true, true); + } + + private void InitActorRoot() + { + var actorRoot = GameObject.Find("ActorRoot"); + if (actorRoot == null) + { + actorRoot = new GameObject("ActorRoot"); + Object.DontDestroyOnLoad(actorRoot); + ActorRootTrans = actorRoot.transform; + ActorRootTrans.position = Vector3.zero; + ActorRootTrans.rotation = Quaternion.identity; + ActorRootTrans.localScale = Vector3.one; + } + } + + private void RefreshActorVisible() + { + } + + public GameObject CreateGameObject(GameActor gameActor) + { + string name = gameActor.GetGameObjectName(); + GameObject actorGo = new GameObject(name); + var trans = actorGo.transform; + trans.parent = ActorRootTrans; + trans.localPosition = Vector3.zero; + trans.localRotation = Quaternion.identity; + trans.localScale = Vector3.one; + return actorGo; + } + + private uint AllocClientGid() + { + ++_clientGid; + if (_clientGid >= ClientGidEnd) + { + _clientGid = ClientGidStart; + } + return _clientGid; + } + + public void AddClientActor(GameActor actor) + { + if (actor == null) + { + return; + } + + RemoveClientActor(actor); + actor.ActorId = AllocClientGid(); + _actorPool.Add(actor.ActorId, actor); + _listActor.Add(actor); + if (actor.gameObject != null) + { + _goModelHash2Actor[actor.gameObject.GetHashCode()] = actor; + } + } + + public void RemoveClientActor(GameActor actor) + { + if (actor == null) + { + return; + } + + _actorPool.Remove(actor.ActorId); + _listActor.Remove(actor); + if (actor.gameObject != null) + { + _goModelHash2Actor.Remove(actor.gameObject.GetHashCode()); + } + } + + public GameActor GetActor(uint actorGID) + { + GameActor actor = null; + _actorPool.TryGetValue(actorGID, out actor); + return actor; + } + + public GameActor GetActor(GameObject go) + { + GameActor actor; + if (_goModelHash2Actor.TryGetValue(go.GetHashCode(), out actor)) + { + return actor; + } + + return null; + } + + public void BindGameActorGo(GameActor actor, GameObject go) + { + _goModelHash2Actor[go.GetHashCode()] = actor; + } + + public GameActor GetMainPlayer() + { + return _mainPlayer; + } + + #region Methods + + public bool DestroyActor(GameActor actor) + { + return DestroyActor(actor.ActorId); + } + + public GameActor CreateGameActor(int actorType, uint actorID, bool isMainPlayer) + { + GameActor ret = null; + + GameActor actorSave; + if (_actorPool.TryGetValue(actorID, out actorSave)) + { + var oldActor = _actorPool[actorID]; + var oldActorType = oldActor.GetActorType(); + Log.Error("duplicate actor gid {0} {1} {2}", actorID, actorType, oldActorType); + if (oldActorType != actorType) + { + DestroyActor(actorID); + ret = CreateGameActor(actorType, actorID); + } + else + { + ret = _actorPool[actorID]; + } + } + else + { + ret = CreateGameActor(actorType, actorID); + } + + if (ret == null) + { + Log.Error("create actor failed, type is {0}, id is {1}", actorType, actorID); + return null; + } + + if (isMainPlayer) + { + SetMainPlayer(ret); + } + + return ret; + } + + private GameActor CreateGameActor(int actorType, uint actorID) + { + GameActor newActor = null; + + if (_actorTypes.TryGetValue(actorType, out var type)) + { + newActor = System.Activator.CreateInstance(type) as GameActor; + } + else + { + Log.Error("unknown actor type:{0}", actorType); + } + + if (newActor != null) + { + newActor.ActorId = actorID; + _actorPool.Add(actorID, newActor); + _listActor.Add(newActor); + } + + return newActor; + } + + public bool DestroyActor(uint actorID) + { + GameActor actor = null; + if (_actorPool.TryGetValue(actorID, out actor)) + { + if (actor == _mainPlayer) + { + SetMainPlayer(null); + } + + if (actor.gameObject != null) + { + _goModelHash2Actor.Remove(actor.gameObject.GetHashCode()); + } + + actor.Destroy(); + _actorPool.Remove(actorID); + _listActor.Remove(actor); + return true; + } + + return false; + } + + private void SetMainPlayer(GameActor actor) + { + _mainPlayer = actor; + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs.meta new file mode 100644 index 00000000..0c28bb85 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 229662c5312943abbe0f2e01d993c6dd +timeCreated: 1663577914 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs b/Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs new file mode 100644 index 00000000..7c972bef --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs @@ -0,0 +1,554 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace TEngine.Runtime.Actor +{ + public enum TimerType + { + TimerTime = 0, + TimerFrameUpdate, + TimerFrameLateUpdate, + TimerFrameOnceUpdate, + TimerUnscaledTime, + } + + public class GameTimer + { + public GameTimer Next; + public GameTimer Prev; + public string DebugSourceName; + public Action CallAction; + public bool Destroyed; + public bool Loop; + public float Interval; + public float TriggerTime; + public bool InExeQueue; + public TimerType timerType; + + public static bool IsNull(GameTimer gameTimer) + { + return gameTimer == null || gameTimer.Destroyed; + } + } + + public class GameTimerList + { + public GameTimer Head; + public GameTimer Tail; + + public int Count = 0; + + public bool IsEmpty + { + get { return Head == null; } + } + + public void AddTail(GameTimer node) + { + var tail = Tail; + if (tail != null) + { + tail.Next = node; + node.Prev = tail; + } + else + { + Head = node; + } + + Tail = node; + AddCount(); + } + + + private void AddCount() + { + Count++; + } + + public void DecCount(int sub = 1) + { + Count -= sub; + Log.Assert(Count >= 0); + } + + public void AddSorted(GameTimer node, float triggerTime) + { + Log.Assert(node.Prev == null); + Log.Assert(node.Next == null); + + node.TriggerTime = triggerTime; + + var head = Head; + while (head != null) + { + if (head.TriggerTime >= triggerTime) + { + break; + } + + head = head.Next; + } + + if (head != null) + { + var prev = head.Prev; + if (prev != null) + { + prev.Next = node; + } + + node.Prev = prev; + + node.Next = head; + head.Prev = node; + + if (prev == null) + { + Head = node; + } + + AddCount(); + } + else + { + AddTail(node); + } + } + + public void Remove(GameTimer node) + { + var prev = node.Prev; + var next = node.Next; + + if (prev != null) + { + prev.Next = next; + } + + if (next != null) + { + next.Prev = prev; + } + + node.Next = null; + node.Prev = null; + + if (Head == node) + { + Head = next; + } + + if (Tail == node) + { + Tail = prev; + } + + DecCount(); + } + + public void Clear() + { + Head = null; + Tail = null; + Count = 0; + } + } + + public class ActorTimerMgr : BehaviourSingleton + { + private GameTimerList _runningList = new GameTimerList(); + private GameTimerList _frameUpdateList = new GameTimerList(); + private GameTimerList _frameLateUpdateList = new GameTimerList(); + private GameTimerList _frameOnceUpdateList = new GameTimerList(); + private GameTimerList _unscaleRunningList = new GameTimerList(); + + public override void Awake() + { + DoCreateLoopTimer("TimerDebug", 10f, () => + { + var totalCount = _frameUpdateList.Count + _frameLateUpdateList.Count + + +_frameOnceUpdateList.Count + _runningList.Count + _unscaleRunningList.Count; + + int maxTriggerCount = 2000; + if (totalCount > maxTriggerCount) + { + Log.Fatal("Timer is overflow: {0}", totalCount); + } + }); + } + + #region 创建定时器接口 + + public bool CreateLoopTimer(ref GameTimer result, string source, float interval, Action timerAction) + { + if (!GameTimer.IsNull(result)) + { + return false; + } + + result = DoCreateLoopTimer(source, interval, timerAction); + return true; + } + + private GameTimer DoCreateLoopTimer(string source, float interval, Action timerAction) + { + interval = Math.Max(interval, 0.001f); + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerTime; + timer.Loop = true; + timer.Interval = interval; + var triggerTime = Time.time + interval; + _runningList.AddSorted(timer, triggerTime); + return timer; + } + + public GameTimer CreateOnceTimer(string source, float elapse, Action timerAction) + { + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerTime; + var triggerTime = Time.time + elapse; + _runningList.AddSorted(timer, triggerTime); + return timer; + } + + /// + /// 修改定时器循环创建接口,改为更加安全的方式 + /// + /// + /// + /// + public bool CreateLoopFrameTimer(ref GameTimer result, string source, Action timerAction) + { + if (!GameTimer.IsNull(result)) + { + return false; + } + + result = DoCreateLoopFrameTimer(source, timerAction); + return true; + } + + private GameTimer DoCreateLoopFrameTimer(string source, Action timerAction) + { + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerFrameUpdate; + _frameUpdateList.AddTail(timer); + return timer; + } + + public GameTimer CreateOnceFrameTimer(string source, Action timerAction) + { + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerFrameOnceUpdate; + _frameOnceUpdateList.AddTail(timer); + return timer; + } + + public bool CreateLoopFrameLateTimer(ref GameTimer result, string source, Action timerAction) + { + if (!GameTimer.IsNull(result)) + { + return false; + } + + result = DoCreateLoopFrameLateTimer(source, timerAction); + return true; + } + + private GameTimer DoCreateLoopFrameLateTimer(string source, Action timerAction) + { + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerFrameLateUpdate; + _frameLateUpdateList.AddTail(timer); + return timer; + } + + /// + /// 不受 + /// + /// + /// + /// + /// + public GameTimer CreateUnscaleLoopTimer(string source, float interval, Action timerAction) + { + interval = Math.Max(interval, 0.001f); + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerUnscaledTime; + timer.Loop = true; + timer.Interval = interval; + var triggerTime = Time.unscaledTime + interval; + _unscaleRunningList.AddSorted(timer, triggerTime); + return timer; + } + + public GameTimer CreateUnscaleOnceTimer(string source, float elapse, Action timerAction) + { + var timer = AllocTimer(source, timerAction); + timer.timerType = TimerType.TimerUnscaledTime; + var triggerTime = Time.unscaledTime + elapse; + _unscaleRunningList.AddSorted(timer, triggerTime); + return timer; + } + + #endregion + + #region 销毁定时器接口 + + public void DestroyTimer(ref GameTimer gameTimer) + { + ProcessDestroyTimer(gameTimer); + gameTimer = null; + } + + private void ProcessDestroyTimer(GameTimer gameTimer) + { + if (gameTimer == null || gameTimer.Destroyed) + { + return; + } + + DoDestroy(gameTimer); + + if (!gameTimer.InExeQueue) + { + var type = gameTimer.timerType; + if (type == TimerType.TimerTime) + { + _runningList.Remove(gameTimer); + } + else if (type == TimerType.TimerFrameUpdate) + { + _frameUpdateList.Remove(gameTimer); + } + else if (type == TimerType.TimerFrameOnceUpdate) + { + _frameOnceUpdateList.Remove(gameTimer); + } + else if (type == TimerType.TimerUnscaledTime) + { + _unscaleRunningList.Remove(gameTimer); + } + else + { + Log.Assert(type == TimerType.TimerFrameLateUpdate); + _frameLateUpdateList.Remove(gameTimer); + } + } + else + { + Log.Debug("Free when in exuete queue"); + } + } + + #endregion + + public override bool IsHaveLateUpdate() + { + return true; + } + + public override void LateUpdate() + { + UpdateFrameTimer(_frameLateUpdateList); + } + + public override void Update() + { + TProfiler.BeginSample("UpdateTickTimer"); + UpdateTickTimer(false); + TProfiler.EndSample(); + + TProfiler.BeginSample("UpdateUnscaleTickTimer"); + UpdateTickTimer(true); + TProfiler.EndSample(); + + TProfiler.BeginSample("UpdateFrameTimer"); + UpdateFrameTimer(_frameUpdateList); + TProfiler.EndSample(); + + TProfiler.BeginSample("UpdateOnceFrameTimer"); + UpdateOnceFrameTimer(_frameOnceUpdateList); + TProfiler.EndSample(); + } + + private void UpdateTickTimer(bool isUnscaled) + { + var runningList = isUnscaled ? _unscaleRunningList : _runningList; + var head = runningList.Head; + if (head != null) + { + var nowTime = isUnscaled ? Time.unscaledTime : Time.time; + var node = head; + + int delCount = 0; + while (node != null && node.TriggerTime <= nowTime) + { + Log.Assert(!node.Destroyed); + node.InExeQueue = true; + node = node.Next; + + delCount++; + } + + if (head == node) + { + Log.Assert(delCount <= 0); + return; + } + + GameTimer waitExeHead = null; + if (node != null) + { + var prev = node.Prev; + prev.Next = null; + + node.Prev = null; + runningList.Head = node; + + runningList.DecCount(delCount); + Log.Assert(runningList.Count >= 0); + + waitExeHead = head; + } + else + { + waitExeHead = head; + runningList.Clear(); + } + + node = waitExeHead; + while (node != null) + { + var next = node.Next; + node.Next = null; + node.Prev = null; + + if (!node.Destroyed) + { + TProfiler.BeginFirstSample(node.DebugSourceName); + + node.CallAction(); + + TProfiler.EndFirstSample(); + + if (node.Loop && !node.Destroyed) + { + node.InExeQueue = false; + var triggerTime = node.Interval + nowTime; + runningList.AddSorted(node, triggerTime); + } + else + { + DoDestroy(node); + } + } + else + { + Log.Debug("destroy timer: {0}", node.DebugSourceName); + } + + node = next; + } + } + } + + private void PrintTimerListStatic(GameTimerList list) + { + Dictionary dictStat = new Dictionary(); + var node = list.Head; + while (node != null) + { + var count = 0; + dictStat.TryGetValue(node.DebugSourceName, out count); + count++; + + dictStat[node.DebugSourceName] = count; + node = node.Next; + } + + var itr = dictStat.GetEnumerator(); + while (itr.MoveNext()) + { + Log.Warning("{0}:{1}", itr.Current.Key, itr.Current.Value); + } + itr.Dispose(); + } + + private void UpdateFrameTimer(GameTimerList list) + { + if (list == null) + { + return; + } + + var node = list.Head; + while (node != null) + { + Log.Assert(!node.Destroyed, node.DebugSourceName); + + node.InExeQueue = true; + + TProfiler.BeginSample(node.DebugSourceName); + + if (node.CallAction != null) + { + node.CallAction(); + } + + TProfiler.EndSample(); + + node.InExeQueue = false; + + var next = node.Next; + if (node.Destroyed) + { + Log.Debug("timer is destroy when loop, free it"); + list.Remove(node); + } + + node = next; + } + } + + private void UpdateOnceFrameTimer(GameTimerList list) + { + var node = list.Head; + list.Clear(); + + while (node != null) + { + Log.Assert(!node.Destroyed); + + node.InExeQueue = true; + + TProfiler.BeginFirstSample(node.DebugSourceName); + + node.CallAction(); + + TProfiler.EndFirstSample(); + + var next = node.Next; + DoDestroy(node); + node = next; + } + } + + + private void DoDestroy(GameTimer gameTimer) + { + gameTimer.Destroyed = true; + gameTimer.CallAction = null; + } + + private GameTimer AllocTimer(string source, Action timerAction) + { + var freeHead = new GameTimer(); + freeHead.CallAction = timerAction; + freeHead.DebugSourceName = source; + return freeHead; + } + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs.meta new file mode 100644 index 00000000..13878ab0 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/ActorTimerMgr.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8b9600b871d94b468afbd03e9ef3fbf0 +timeCreated: 1663557236 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs b/Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs new file mode 100644 index 00000000..1a5e15dc --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs @@ -0,0 +1,277 @@ +using System; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace TEngine.Runtime.Actor +{ + /// + /// 游戏对象(GameActor) + /// + public abstract partial class GameActor + { + #region Propreties + public uint ActorId { get; set; } + + public bool IsCreated { get; set; } + + public byte ActorSide; + + public abstract int GetActorType(); + + public bool IsDestroyed { get; set; } + + public string Name = string.Empty; + + private ActorEventDispatcher _event = new ActorEventDispatcher(); + + public ActorEventDispatcher Event => _event; + + private GameObject _gameObject; + + public GameObject gameObject => _gameObject; + + private float _visibleTime = 0; + + private bool _visible; + + public bool Visible + { + get { return _visible; } + set + { + if (_gameObject == null) + { + return; + } + + if (_visible != value) + { + _visible = value && CheckActorCanVisible(); + if (_visible && _visibleTime <= 0.0001f) + { + _visibleTime = Time.time; + } + Event.SendEvent(ActorEventType.ModelVisibleChange, _visible); + } + } + } + + public virtual bool CheckActorCanVisible() + { + return true; + } + + public string GetGameObjectName() + { +#if UNITY_EDITOR + return string.Format("[{0}][{1}][{2}]", ActorId, GetActorType(), GetActorName()); +#else + return "GameActor"; +#endif + } + + public virtual string GetActorName() + { + return "UNNAMED"; + } + #endregion + + #region Actions + public Action Awake; + public Action OnInit; + public Action AfterInit; + #endregion + + #region Transform + public Transform transform + { + get + { + if (gameObject == null) + { + throw new Exception("Runtime GameActor gameObject is Null"); + } + + return gameObject.transform; + } + } + + public Vector3 Position + { + get + { + if (transform == null) + { + throw new Exception("Runtime GameActor transform is Null"); + } + + return transform.position; + } + set + { + if (transform == null) + { + throw new Exception("Runtime GameActor transform is Null"); + } + + transform.position = value; + } + } + + public Vector3 Forward + { + get + { + if (transform == null) + { + throw new Exception("Runtime GameActor transform is Null"); + } + + return transform.forward; + } + set + { + if (transform == null) + { + throw new Exception("Runtime GameActor transform is Null"); + } + + transform.forward = value; + } + } + + public Vector3 LocalScale + { + get + { + if (transform == null) + { + throw new Exception("Runtime GameActor transform is Null"); + } + + return transform.localScale; + } + set + { + if (transform == null) + { + throw new Exception("Runtime GameActor transform is Null"); + } + + transform.localScale = value; + } + } + + public Quaternion Rotation + { + get + { + if (transform != null) + { + return transform.rotation; + } + + return Quaternion.identity; + } + set + { + if (transform != null) + { + transform.rotation = value; + } + } + } + #endregion + + #region Init + public GameActor() + { + + } + + protected virtual GameObject CreateGameObject() + { + return ActorManager.Instance.CreateGameObject(this); + } + + protected void BaseInit() + { + if (_gameObject == null) + { + _visible = false; + + _gameObject = CreateGameObject(); + + ActorManager.Instance.BindGameActorGo(this,_gameObject); + } + InitExt(); + } + + + #endregion + + #region Methods + + public void Destroy() + { + Visible = false; + + _isDestroying = true; + + BeforeDestroyAllComponent(); + + DestroyAllComponent(); + + if (gameObject != null) + { + Object.Destroy(_gameObject); + + _gameObject = null; + } + + IsDestroyed = true; + _isDestroying = false; + } + #endregion + + #region Expand + + #region Base + public static bool operator ==(GameActor obj1, GameActor obj2) + { + if (ReferenceEquals(obj1, obj2)) + { + return true; + } + + bool isObj1Null = ReferenceEquals(obj1, null) || obj1.IsDestroyed; + bool isObj2Null = ReferenceEquals(obj2, null) || obj2.IsDestroyed; + return isObj1Null && isObj2Null; + } + + public static bool operator !=(GameActor obj1, GameActor obj2) + { + return !(obj1 == obj2); + } + + public override bool Equals(object obj2) + { + bool isObj1Null = IsDestroyed; + bool isObj2Null = ReferenceEquals(obj2, null); + if (isObj1Null && isObj2Null) + { + return true; + } + + return ReferenceEquals(this, obj2); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + #endregion + + #endregion + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs.meta new file mode 100644 index 00000000..ac0b4a89 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/GameActor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9bf64870c7814cedabaf3be95c0165c2 +timeCreated: 1663555405 \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs b/Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs new file mode 100644 index 00000000..f196e89c --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; + +namespace TEngine.Runtime.Actor +{ + public abstract partial class GameActor + { + public ActorAttribute Attr = new ActorAttribute(); + private readonly List _listComponents = new List(); + private readonly Dictionary _mapComponents = new Dictionary(); + private bool _isDestroying = false; + + protected void InitExt() + { + _isDestroying = false; + } + + #region component + + public T AddComponent() where T : ActorComponent, new() + { + if (IsDestroyed || _isDestroying) + { + Log.Fatal("Actor is destroyed, cant add component: {0}, Is Destroying[{1}]", + GetClassName(typeof(T)), _isDestroying); + return null; + } + + T component = GetComponent(); + if (component != null) + { + return component; + } + + component = ActorComponentPool.Instance.AllocComponent(); + if (!AddComponentImp(component)) + { + Log.Warning("AddComponent failed, Component name: {0}", GetClassName(typeof(T))); + component.BeforeDestroy(); + ActorComponentPool.Instance.FreeComponent(component); + return null; + } + + return component; + } + + public T GetComponent() where T : ActorComponent + { + ActorComponent component; + if (_mapComponents.TryGetValue(GetClassName(typeof(T)), out component)) + { + return component as T; + } + + return null; + } + + public void RemoveComponent() where T : ActorComponent + { + if (_isDestroying) + { + Log.Debug("GameActor[{0}] is destroying, no need destroy component anyway", Name); + return; + } + + string className = GetClassName(typeof(T)); + ActorComponent component; + if (_mapComponents.TryGetValue(className, out component)) + { + component.BeforeDestroy(); + + Event.RemoveAllListenerByOwner(component); + _mapComponents.Remove(className); + _listComponents.Remove(component); + + ActorComponentPool.Instance.FreeComponent(component); + } + } + + private bool AddComponentImp(T component) where T : ActorComponent + { + if (!component.BeforeAddToActor(this)) + { + return false; + } + + _listComponents.Add(component); + _mapComponents[GetClassName(typeof(T))] = component; + return true; + } + + private string GetClassName(Type type) + { + return type.FullName; + } + + private void BeforeDestroyAllComponent() + { + var listCmpt = _listComponents; + for (int i = listCmpt.Count - 1; i >= 0; i--) + { + listCmpt[i].BeforeDestroy(); + } + } + + private void DestroyAllComponent() + { + var componentPool = ActorComponentPool.Instance; + + var listComponents = _listComponents; + for (int i = listComponents.Count - 1; i >= 0; i--) + { + componentPool.FreeComponent(listComponents[i]); + } + _listComponents.Clear(); + _mapComponents.Clear(); + } + #endregion + } +} \ No newline at end of file diff --git a/Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs.meta b/Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs.meta new file mode 100644 index 00000000..31d25108 --- /dev/null +++ b/Assets/TEngine/Scripts/Runtime/Actor/GameActorExt.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f4aeb507ce5b4cb596451316dc069212 +timeCreated: 1663558112 \ No newline at end of file