using Cryville.Common; using Cryville.Common.Buffers; using Cryville.Common.Collections.Specialized; using Cryville.Common.Pdt; using Cryville.Crtr.Ruleset; using Cryville.Crtr.Skin; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; namespace Cryville.Crtr.Event { public class ContainerState { #region Struct public EventBus Bus; public EventContainer Container; public StampedEvent StampedContainer; public ContainerState Parent = null; public ushort Depth; public Dictionary Children = new(); HashSet ActiveChildren = new(); public Dictionary> TypedChildren = new(); public ContainerState GetChild(int index, Type handlerType) { var list = TypedChildren[handlerType]; if (index < 0 || index >= list.Count) throw new ArgumentOutOfRangeException("index", string.Format("{0}#{1} does not exist.", list[0].Handler.TypeName, index)); return list[index]; } private bool m_active; public bool Active { get { return m_active; } private set { if (m_active == value) return; m_active = value; if (!m_active) { if (CloneType == 1) Dispose(); else if (CloneType >= 16) ReleasePools(); } if (Parent != null) { if (m_active) Parent.ActiveChildren.Add(Container); else Parent.ActiveChildren.Remove(Container); } Bus.NotifyActiveChanged(this); } } private bool m_lActive; public bool LogicalActive { get { return m_lActive; } set { if (m_lActive == value) return; m_lActive = value; UpdateActive(); if (m_lActive) Handler.StartLogicalUpdate(this); else Handler.EndLogicalUpdate(this); } } private bool m_pActive; public bool PhysicalActive { get { return m_pActive; } set { if (m_pActive == value) return; m_pActive = value; UpdateActive(); if (m_pActive) Handler.StartPhysicalUpdate(this); else Handler.EndPhysicalUpdate(this); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] void UpdateActive() { Active = m_lActive || m_pActive; } public byte CloneType; public ContainerState rootPrototype = null; public ContainerHandler Handler { get; private set; } public double Time { get { return Bus.Time; } } public ContainerState(EventContainer _ev, ContainerState parent = null) { Container = _ev; if (parent != null) { AddChild(_ev, parent); Parent = parent; } _rmvpa = new CategorizedPoolAccessor(RMVPool.Shared); _mcpa = new CategorizedPoolAccessor(MotionCachePool.Shared); Values = new IntKeyedDictionary(ChartPlayer.motionRegistry.Count); CachedValues = new IntKeyedDictionary(ChartPlayer.motionRegistry.Count); foreach (var m in ChartPlayer.motionRegistry) Values.Add(m.Key.Key, new RealtimeMotionValue().Init(Parent == null ? m.Value.GlobalInitValue : m.Value.InitValue)); rootPrototype = this; } void AddChild(EventContainer c, ContainerState parent) { parent.Children.Add(c, this); Type t = c.GetType(); if (!parent.TypedChildren.TryGetValue(t, out List tc)) parent.TypedChildren.Add(t, tc = new List()); tc.Add(this); } public ContainerState Clone(byte ct) { var r = (ContainerState)MemberwiseClone(); var mvs = new IntKeyedDictionary(ChartPlayer.motionRegistry.Count); foreach (var mv in Values) { mvs.Add(mv.Key, mv.Value.Clone()); } r.Values = mvs; var cvs = new IntKeyedDictionary(ChartPlayer.motionRegistry.Count); r.CachedValues = cvs; r.Children = new Dictionary(); r.TypedChildren = new Dictionary>(); foreach (var child in Children) { var cc = child.Value.Clone(ct); cc.Parent = r; cc.AddChild(child.Key, r); } r.ActiveChildren = new HashSet(); var pms = new Dictionary(Math.Max(4, PlayingMotions.Count)); foreach (var m in PlayingMotions) pms.Add(m.Key, m.Value); r.PlayingMotions = pms; if (ct == 1) Handler.bs = r; else if (ct == 2) Handler.ts = r; else if (ct == 3) Handler.ns = r; else if (ct >= 16) Handler.ps = r; else throw new InvalidOperationException("Invalid clone type"); r.CloneType = ct; return r; } public void CopyTo(ContainerState dest) { dest.m_lActive = m_lActive; dest.m_pActive = m_pActive; dest.m_active = m_active; if (dest.m_active) dest.Bus.NotifyActiveChanged(dest); foreach (var mv in Values) { if (dest.Values.TryGetValue(mv.Key, out RealtimeMotionValue dv)) mv.Value.CopyTo(dv, false); else dest.Values.Add(mv.Key, mv.Value.Clone()); } foreach (var cv in dest.CachedValues) cv.Value.Valid = false; foreach (var cv in CachedValues) { if (!dest.CachedValues.TryGetValue(cv.Key, out MotionCache dv)) { dest.CachedValues.Add(cv.Key, dv = dest._mcpa.Rent(cv.Key)); } cv.Value.CopyTo(dv); } foreach (var cev in dest.ActiveChildren) { if (!ActiveChildren.Contains(cev)) Children[cev].CopyTo(dest.Children[cev]); } dest.ActiveChildren.Clear(); foreach (var cev in ActiveChildren) { dest.ActiveChildren.Add(cev); Children[cev].CopyTo(dest.Children[cev]); } foreach (var m in dest.PlayingMotions) { if (m.Value.CloneTypeFlag == dest.CloneType) dest._rmvpa.Return(m.Value); } dest.PlayingMotions.Clear(); foreach (var m in PlayingMotions) { dest.PlayingMotions.Add(m.Key, m.Value); } } public bool Disposed { get; private set; } public void Dispose() { if (Disposed) return; Disposed = true; if (CloneType == 1) Handler.Dispose(); ReleasePools(); foreach (var s in Children) s.Value.Dispose(); } public void DisposeAll() { foreach (var s in Children) s.Value.DisposeAll(); Handler.DisposeAll(); } public void ReleasePools() { _rmvpa.ReturnAll(); _mcpa.ReturnAll(); } public void AttachHandler(ContainerHandler h) { if (Handler != null) throw new InvalidOperationException("Handler attached twice"); Handler = h; h.cs = this; } public void AttachSystems(PdtSkin skin, Judge judge) { Handler.AttachSystems(skin, judge); } #endregion #region Motion readonly CategorizedPoolAccessor _rmvpa; readonly CategorizedPoolAccessor _mcpa; Dictionary PlayingMotions = new(4); IntKeyedDictionary Values; IntKeyedDictionary CachedValues; void InvalidateMotion(int name) { if (!CachedValues.TryGetValue(name, out MotionCache cache)) CachedValues.Add(name, cache = _mcpa.Rent(name)); cache.Valid = false; foreach (var c in ActiveChildren) Children[c].InvalidateMotion(name); } public Vector GetComputedValue(int key) { if (!CachedValues.TryGetValue(key, out MotionCache tr)) CachedValues.Add(key, tr = _mcpa.Rent(key)); Vector r = tr.Value; if (tr.Valid) return r; Values[key].Compute(ref r); if (Parent != null) r.ApplyFrom(Parent.GetComputedValue(key)); tr.Valid = true; return r; } public T GetComputedValue(int key) where T : Vector { return (T)GetComputedValue(key); } static readonly int n_pt = IdentifierManager.Shared.Request("pt"); public Vector2 ScreenPoint { get { var mv = GetComputedValue(n_pt); return mv.ToVector2(); } } static readonly int n_dir = IdentifierManager.Shared.Request("dir"); public Vector3 Direction { get { Vec3 r = GetComputedValue(n_dir); return r.ToVector3(); } } static readonly int n_normal = IdentifierManager.Shared.Request("normal"); public Vector3 Normal { get { Vec3 r = GetComputedValue(n_normal); return r.ToVector3(); } } public Quaternion QuatDir { get { return Quaternion.LookRotation(Quaternion.Euler(Direction) * Vector3.forward, Normal); } } static readonly int n_sv = IdentifierManager.Shared.Request("sv"); static readonly int n_svm = IdentifierManager.Shared.Request("svm"); public float ScrollVelocity { get { return GetComputedValue(n_sv).Value * GetComputedValue(n_svm).Value; } } static readonly int n_dist = IdentifierManager.Shared.Request("dist"); public float Distance { get { return GetComputedValue(n_dist).Value; } } static readonly int n_track = IdentifierManager.Shared.Request("track"); public float Track { get { return GetComputedValue(n_track).Value; } } #endregion #region Update bool breakflag = false; public void Break() { // Handler.EndLogicalUpdate(this); breakflag = true; // LogicalActive = false; } public void Discard(StampedEvent ev) { Handler.Discard(this, ev); if (ev is StampedEvent.RelativeMotion motion) { ReturnRelativeMotionEvent(motion); } else if (ev.Origin is StampedEvent.RelativeMotion) { ReturnEndRelativeMotionEvent((StampedEvent.Temporary)ev); } } public void Handle(StampedEvent ev) { if (breakflag) return; if (ev != null) { if (ev.Unstamped is Chart.Motion) { var tev = (Chart.Motion)ev.Unstamped; var mv = _rmvpa.Rent(tev.Name.Key); mv.CloneTypeFlag = CloneType; Values[tev.Name.Key].CopyTo(mv, true); PlayingMotions.Add(ev, mv); Update(ev); if (!ev.Unstamped.IsLong) { PlayingMotions.Remove(ev); _rmvpa.Return(mv); } } else if (ev is StampedEvent.RelativeMotion tev) { var mv = _rmvpa.Rent(tev.Name); mv.CloneTypeFlag = CloneType; Values[tev.Name].CopyTo(mv, true); PlayingMotions.Add(ev, mv); Update(ev); if (ev.Duration == 0) { PlayingMotions.Remove(ev); _rmvpa.Return(mv); ReturnRelativeMotionEvent(tev); } } else if (ev.Unstamped is EventContainer) { var cev = (EventContainer)ev.Unstamped; var ccs = Children[cev]; ccs.LogicalActive = true; UpdateMotions(); if (!cev.IsLong) { ccs.LogicalActive = false; } } else if (ev.Origin != null) { var oev = ev.Origin; if (oev is StampedEvent.RelativeMotion motion) { Update(ev); var mv = PlayingMotions[oev]; if (mv.CloneTypeFlag == CloneType) _rmvpa.Return(mv); PlayingMotions.Remove(oev); ReturnEndRelativeMotionEvent((StampedEvent.Temporary)ev); ReturnRelativeMotionEvent(motion); } else { var nev = oev.Unstamped; if (nev is Chart.Motion) { Update(ev); var mv = PlayingMotions[oev]; if (mv.CloneTypeFlag == CloneType) _rmvpa.Return(mv); PlayingMotions.Remove(oev); } else if (nev is EventContainer cev) { var ccs = Children[cev]; UpdateMotions(); ccs.LogicalActive = false; } } } Update(ev.Unstamped == null || ev.Unstamped.Priority >= 0 ? ev : null); } else Update(null); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void Update(StampedEvent ev) { UpdateMotions(); Handler.Update(this, ev); } private void UpdateMotions() { foreach (var m in PlayingMotions) { if (m.Key is StampedEvent.RelativeMotion) { var tev = (StampedEvent.RelativeMotion)m.Key; var value = Values[tev.Name]; InvalidateMotion(tev.Name); if (tev.Duration == 0) { tev.Node.Value.CopyTo(value.RelativeValue); } else { var scaledTime = (float)((Time - tev.Time) / tev.Duration); var transition = GetTransition(scaledTime, tev.Node.Transition); tev.Node.Value.LerpWith(m.Value.RelativeValue, transition, ref value.RelativeValue); } } else { var tev = (Chart.Motion)m.Key.Unstamped; if (tev.Node.Id >= 0 && (CloneType == 2 || CloneType == 3)) continue; var value = Values[tev.Name.Key]; InvalidateMotion(tev.Name.Key); if (m.Key.Duration == 0) { if (tev.Node.Id >= 0) { if (CloneType != 0) continue; value.SetRelativeNode(tev.Node); } else { tev.Node.Value.CopyTo(value.AbsoluteValue); } } else { var scaledTime = (float)((Time - m.Key.Time - ChartPlayer.actualRenderStep * tev.sumfix) / m.Key.Duration); var transition = GetTransition(scaledTime, tev.transition); if (tev.Node.Id >= 0) { if (CloneType != 0) continue; var start = m.Value.GetRelativeNode(tev.Node.Id); if (start == null) { value.SetRelativeNode(tev.Node); } else { var target = value.GetRelativeNode(tev.Node.Id); if (target == null) value.SetRelativeNode(tev.Node); else tev.Node.LerpWith(start, transition, ref target); } } else { tev.Node.Value.LerpWith(m.Value.AbsoluteValue, transition, ref value.AbsoluteValue); } } } } } static readonly PropStores.Float _ttimest = new(); static readonly PropStores.Vector4 _transst = new(); Vector4 GetTransition(float time, PdtExpression transition) { if (time >= 1) return Vector4.one; if (transition == null) return new Vector4(time, time, time, time); _ttimest.Value = time; PdtEvaluator.Instance.ContextSelfValue = _ttimest.Source; PdtEvaluator.Instance.Evaluate(_transst.Target, transition); PdtEvaluator.Instance.ContextSelfValue = null; return _transst.Value; } public void BroadcastPreInit() { Handler.PreInit(); foreach (var c in Children) { c.Value.BroadcastPreInit(); } } public void BroadcastPostInit() { Handler.PostInit(); foreach (var c in Children) { c.Value.BroadcastPostInit(); } } public void EndPreGraphicalUpdate() { Handler.SetPreGraphicalActive(false, this); foreach (var ls in ActiveChildren) { Children[ls].EndPreGraphicalUpdate(); } } public void EndGraphicalUpdate() { Handler.SetGraphicalActive(false, this); foreach (var ls in ActiveChildren) { Children[ls].EndGraphicalUpdate(); } } static readonly SimpleObjectPool relmEvPool = new(1024); static readonly SimpleObjectPool erelmEvPool = new(1024); public void PreAnchor() { PushRelativeMotions(Handler.ns.Bus); Handler.PreAnchor(); foreach (var ls in Children) { if (ls.Value.Handler.Alive) ls.Value.PreAnchor(); } } public void Anchor() { PushRelativeMotions(Handler.ts.Bus); Handler.Anchor(); foreach (var ls in Children) { if (ls.Value.Handler.Alive) ls.Value.Anchor(); } } void PushRelativeMotions(EventBus bus) { foreach (var m in Values) { foreach (var node in m.Value.RelativeNodes) { var ev = relmEvPool.Rent(); ev.Time = rootPrototype.Time + node.Value.Time.Value; ev.Container = Container; ev.Name = m.Key; ev.Node = node.Value; bus.PushTempEvent(ev); if (node.Value.EndTime.Value > node.Value.Time.Value) { var eev = erelmEvPool.Rent(); eev.Time = rootPrototype.Time + node.Value.EndTime.Value; eev.Container = Container; eev.Origin = ev; ev.ReleaseEvent = eev; bus.PushTempEvent(eev); } } } } void ReturnRelativeMotionEvent(StampedEvent.RelativeMotion ev) { ev.Container = null; ev.Node = null; ev.ReleaseEvent = null; relmEvPool.Return(ev); } void ReturnEndRelativeMotionEvent(StampedEvent.Temporary ev) { ev.Container = null; ev.Origin = null; erelmEvPool.Return(ev); } #endregion } }