using Cryville.Common; using Cryville.Common.Buffers; using Cryville.Crtr.Components; using System; using System.Collections.Generic; using System.Globalization; using System.Runtime.CompilerServices; using UnityEngine; namespace Cryville.Crtr.Event { public abstract class ContainerHandler { #region Struct public ContainerHandler() { } public abstract string TypeName { get; } /// /// Prehandling , prehandling the events. /// public ContainerState ps; /// /// Backward , disposing events at the backward clipping plane, firing anchor state and temporary state. /// public ContainerState bs; /// /// Current , handling events occuring at the current time. /// public ContainerState cs; /// /// Anchor , computing the start position of the temporary state. /// public ContainerState ns; /// /// Temporary , rendering events between the clipping planes. /// public ContainerState ts; /// /// group, the containing all the generated elements in the . /// protected Transform gogroup; public SkinContext SkinContext; public Vector3 Position { get; protected set; } public Quaternion Rotation { get; protected set; } public bool Alive { get; private set; } bool PreGraphicalActive; public void SetPreGraphicalActive(bool value, ContainerState s) { if (PreGraphicalActive == value) return; PreGraphicalActive = value; if (PreGraphicalActive) StartPreGraphicalUpdate(s); else EndPreGraphicalUpdate(s); } bool GraphicalActive; public void SetGraphicalActive(bool value, ContainerState s) { if (GraphicalActive == value) return; GraphicalActive = value; if (GraphicalActive) StartGraphicalUpdate(s); else EndGraphicalUpdate(s); } public EventContainer Container { get { return cs.Container; } } SkinContainer skinContainer; protected Judge judge; public void AttachSystems(PdtSkin skin, Judge judge) { skinContainer = new SkinContainer(skin); this.judge = judge; } public readonly Dictionary> Anchors = new Dictionary>(); public readonly Dictionary DynamicAnchors = new Dictionary(); public readonly Dictionary DynamicAnchorSet = new Dictionary(); public Anchor OpenedAnchor; protected Anchor a_cur; protected Anchor a_head; protected Anchor a_tail; protected readonly static int _a_cur = IdentifierManager.SharedInstance.Request("cur"); protected readonly static int _a_head = IdentifierManager.SharedInstance.Request("head"); protected readonly static int _a_tail = IdentifierManager.SharedInstance.Request("tail"); public Anchor RegisterAnchor(int name, bool dyn = false, int propSrcCount = 0) { var strname = IdentifierManager.SharedInstance.Retrieve(name); var go = new GameObject("." + strname).transform; go.SetParent(gogroup, false); var result = new Anchor(name, go, propSrcCount); if (dyn) { if (DynamicAnchors.ContainsKey(name)) throw new ArgumentException(string.Format("The anchor \"{0}\" already exists", strname)); DynamicAnchors.Add(name, result); DynamicAnchorSet.Add(name, false); } List list; if (!Anchors.TryGetValue(name, out list)) Anchors.Add(name, list = new List()); list.Add(result); return result; } protected void OpenAnchor(Anchor anchor) { if (OpenedAnchor != null) throw new InvalidOperationException("An anchor has been opened"); OpenedAnchor = anchor; } protected void CloseAnchor() { OpenedAnchor = null; } #endregion #region Logic #region Init methods: Called on prehandle public virtual void PreInit() { gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString(CultureInfo.InvariantCulture)).transform; SkinContext = new SkinContext(gogroup); if (cs.Parent != null) gogroup.SetParent(cs.Parent.Handler.gogroup, false); a_cur = RegisterAnchor(_a_cur); a_head = RegisterAnchor(_a_head, true); a_tail = RegisterAnchor(_a_tail, true); } public virtual void Init() { skinContainer.MatchStatic(ps); foreach (var i in gogroup.GetComponentsInChildren()) i.Init(); } public virtual void PostInit() { gogroup.gameObject.SetActive(false); } #endregion #region Start methods public virtual void StartPhysicalUpdate(ContainerState s) { if (s.CloneType < 16) Alive = true; else if (s.CloneType == 17) Init(); } public virtual void StartLogicalUpdate(ContainerState s) { } public virtual void StartPreGraphicalUpdate(ContainerState s) { } public virtual void StartGraphicalUpdate(ContainerState s) { if (gogroup) gogroup.gameObject.SetActive(true); } #endregion public virtual void Update(ContainerState s, StampedEvent ev) { if (s.CloneType == 3) SetPreGraphicalActive(true, s); else if (ev is StampedEvent.Anchor) { var tev = (StampedEvent.Anchor)ev; if (tev.Target == a_head) { SetGraphicalActive(true, s); } else if (tev.Target == a_tail) { SetGraphicalActive(false, s); } if (gogroup) { OpenAnchor(tev.Target); #if UNITY_5_6_OR_NEWER tev.Target.Transform.SetPositionAndRotation(Position, Rotation); #else tev.Target.Transform.position = Position; tev.Target.Transform.rotation = Rotation; #endif skinContainer.MatchDynamic(s); CloseAnchor(); } anchorEvPool.Return(tev); } else if (gogroup && s.CloneType == 2) skinContainer.MatchDynamic(s); } #region End methods public virtual void EndGraphicalUpdate(ContainerState s) { } public virtual void EndPreGraphicalUpdate(ContainerState s) { } public virtual void EndLogicalUpdate(ContainerState s) { } public virtual void EndPhysicalUpdate(ContainerState s) { } public virtual void Dispose() { if (gogroup) GameObject.Destroy(gogroup.gameObject); Alive = false; } public virtual void DisposeAll() { } #endregion [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static bool CanDoGraphicalUpdate(ContainerState s) { return s.CloneType >= 2 && s.CloneType < 16; } #region Anchor public virtual void Anchor() { foreach (var a in DynamicAnchors.Keys) DynamicAnchorSet[a] = false; skinContainer.MatchDynamic(cs); if (cs.Active) PushAnchorEvent(cs.Time, a_cur); if (Alive) { if (!DynamicAnchorSet[_a_head]) PushAnchorEvent(cs.StampedContainer.Time, a_head, -1, true); if (!DynamicAnchorSet[_a_tail]) PushAnchorEvent(cs.StampedContainer.Time + cs.StampedContainer.Duration, a_tail, 1, true); } } static readonly SimpleObjectPool anchorEvPool = new SimpleObjectPool(1024); public void PushAnchorEvent(double time, int name) { Anchor anchor; if (!DynamicAnchors.TryGetValue(name, out anchor)) throw new ArgumentException(string.Format("Specified anchor \"{0}\" not found", IdentifierManager.SharedInstance.Retrieve(name))); if (DynamicAnchorSet[name]) throw new InvalidOperationException(string.Format("Specified anchor \"{0}\" has been set", IdentifierManager.SharedInstance.Retrieve(name))); int priority = 0; bool forced = true; if (name == _a_head) priority = -1; else if (name == _a_tail) priority = 1; else forced = false; PushAnchorEvent(time, anchor, priority, forced); DynamicAnchorSet[name] = true; } void PushAnchorEvent(double time, Anchor anchor, int priority = 0, bool forced = false) { var tev = anchorEvPool.Rent(); tev.Time = time; tev.Container = Container; tev.Target = anchor; tev.CanDiscard = !forced; tev.SetPriority(priority); ts.Bus.PushTempEvent(tev); } public virtual void Discard(ContainerState s, StampedEvent ev) { if (ev is StampedEvent.Anchor) { anchorEvPool.Return((StampedEvent.Anchor)ev); } } #endregion #endregion } }