//#define DISABLE_CACHE using Cryville.Common; using Cryville.Common.Buffers; using Cryville.Common.Collections.Specialized; 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 Dictionary(); HashSet ActiveChildren = new HashSet(); public Dictionary> TypedChildren = new Dictionary>(); public ContainerState GetChild(int index, Type handlerType) { return TypedChildren[handlerType][index]; } public ContainerState GetChild(EventContainer ev) { return Children[ev]; } private bool m_active; public bool Active { get { return m_active; } private set { if (m_active == value) return; m_active = value; if (!m_active && CloneType == 1) Dispose(); 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); _mcpa = new CategorizedPoolAccessor(MCPool); 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(); List tc; if (!parent.TypedChildren.TryGetValue(t, out 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(byte ct, 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) { RealtimeMotionValue dv; if (dest.Values.TryGetValue(mv.Key, out dv)) mv.Value.CopyTo(dv); else dest.Values.Add(mv.Key, mv.Value.Clone()); } foreach (var cv in dest.CachedValues) cv.Value.Valid = false; foreach (var cv in CachedValues) { MotionCache dv; if (!dest.CachedValues.TryGetValue(cv.Key, out 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(ct, dest.Children[cev]); } dest.ActiveChildren.Clear(); foreach (var cev in ActiveChildren) { dest.ActiveChildren.Add(cev); Children[cev].CopyTo(ct, dest.Children[cev]); } 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(); if (CloneType == 1 || CloneType == 17) { _rmvpa.ReturnAll(); _mcpa.ReturnAll(); } foreach (var s in Children) s.Value.Dispose(); } public void DisposeAll() { foreach (var s in Children) s.Value.DisposeAll(); Handler.DisposeAll(); } 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 internal static RMVPool RMVPool; internal static MotionCachePool MCPool; readonly CategorizedPoolAccessor _rmvpa; readonly CategorizedPoolAccessor _mcpa; Dictionary PlayingMotions = new Dictionary(4); IntKeyedDictionary Values; IntKeyedDictionary CachedValues; /// /// Gets a motion value. /// /// The motion name. /// Returns a cloned motion value instead. /// A motion value. RealtimeMotionValue GetMotionValue(int name, bool clone = false) { RealtimeMotionValue value = Values[name]; if (clone) return value.Clone(); return value; } void InvalidateMotion(int name) { MotionCache cache; if (!CachedValues.TryGetValue(name, out cache)) CachedValues.Add(name, cache = _mcpa.Rent(name)); cache.Valid = false; foreach (var c in ActiveChildren) Children[c].InvalidateMotion(name); } public Vector GetRawValue(int key) { MotionCache tr; if (!CachedValues.TryGetValue(key, out tr)) CachedValues.Add(key, tr = _mcpa.Rent(key)); Vector r = tr.Value; #if !DISABLE_CACHE if (tr.Valid) return r; #endif float reltime = 0; if (rootPrototype != null) reltime = (float)(Time - rootPrototype.Time); GetMotionValue(key).GetValue(reltime, ref r); if (Parent != null) r.ApplyFrom(Parent.GetRawValue(key)); #if !DISABLE_CACHE tr.Valid = true; #endif return r; } public T GetRawValue(int key) where T : Vector { return (T)GetRawValue(key); } static readonly int n_pt = IdentifierManager.SharedInstance.Request("pt"); public Vector2 ScreenPoint { get { var mv = GetRawValue(n_pt); return mv.ToVector2(ChartPlayer.hitRect); } } static readonly int n_dir = IdentifierManager.SharedInstance.Request("dir"); public Vector3 Direction { get { Vec3 r = GetRawValue(n_dir); return r.ToVector3(); } } static readonly int n_normal = IdentifierManager.SharedInstance.Request("normal"); public Vector3 Normal { get { Vec3 r = GetRawValue(n_normal); return r.ToVector3(); } } public Quaternion QuatDir { get { return Quaternion.LookRotation(Quaternion.Euler(Direction) * Vector3.forward, Normal); } } static readonly int n_sv = IdentifierManager.SharedInstance.Request("sv"); static readonly int n_svm = IdentifierManager.SharedInstance.Request("svm"); public float ScrollVelocity { get { return GetRawValue(n_sv).ToFloat(ChartPlayer.hitRect) * GetRawValue(n_svm).Value; } } static readonly int n_dist = IdentifierManager.SharedInstance.Request("dist"); public float Distance { get { var mv = GetRawValue(n_dist); return mv.ToFloat(ChartPlayer.hitRect); } } static readonly int n_corner = IdentifierManager.SharedInstance.Request("corner"); public bool Corner { get { return GetRawValue(n_corner).Value % 2 >= 1; } } static readonly int n_ctrl0 = IdentifierManager.SharedInstance.Request("ctrl0"); static readonly int n_ctrl1 = IdentifierManager.SharedInstance.Request("ctrl1"); public Vector3 GetControlPoint(bool alt1, float deltaz) { var mv = GetRawValue(alt1 ? n_ctrl1 : n_ctrl0); if (alt1 && mv.IsZero()) { mv = GetRawValue(n_ctrl0); } return mv.ToVector3(ChartPlayer.hitRect, deltaz); } static readonly int n_track = IdentifierManager.SharedInstance.Request("track"); public float Track { get { return GetRawValue(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); } 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; GetMotionValue(tev.Name.Key).CopyTo(mv); PlayingMotions.Add(ev, mv); Update(ev); if (!ev.Unstamped.IsLong) { PlayingMotions.Remove(ev); _rmvpa.Return(mv); } } else if (ev.Unstamped is EventContainer) { var cev = (EventContainer)ev.Unstamped; var ccs = GetChild(cev); ccs.LogicalActive = true; UpdateMotions(); if (!cev.IsLong) { ccs.LogicalActive = false; } } else if (ev.Unstamped is ReleaseEvent) { var tev = (ReleaseEvent)ev.Unstamped; var nev = tev.Original; if (nev is Chart.Motion) { Update(ev); var mv = PlayingMotions[ev.Origin]; if (mv.CloneTypeFlag == CloneType) _rmvpa.Return(mv); PlayingMotions.Remove(ev.Origin); } else if (nev is EventContainer) { var cev = (EventContainer)ev.Origin.Unstamped; var ccs = GetChild(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) { var tev = (Chart.Motion)m.Key.Unstamped; if (tev.RelativeNode != null && CloneType == 2) continue; var value = GetMotionValue(tev.Name.Key/*, true*/); InvalidateMotion(tev.Name.Key); if (m.Key.Duration == 0) { if (tev.RelativeNode != null) { value.SetRelativeNode(tev.RelativeNode); } else { value.AbsoluteValue.ReplaceFrom(tev.AbsoluteValue); } } else { var scaledTime = (float)((Time - m.Key.Time - ChartPlayer.actualRenderStep * tev.sumfix) / m.Key.Duration); var lerpedTime = MotionLerper.GetEaseTime(scaledTime, tev.transition, tev.rate); if (tev.RelativeNode != null) { var target = value.QueryRelativeNode(tev.RelativeNode.Id); tev.RelativeNode.LerpWith(m.Value.GetRelativeNode(tev.RelativeNode.Id), lerpedTime, ref target); } else { tev.AbsoluteValue.LerpWith(m.Value.AbsoluteValue, lerpedTime, ref value.AbsoluteValue); } } Values[tev.Name.Key] = 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(); } } public void Anchor() { Handler.Anchor(); foreach (var ls in Children) { if (ls.Value.Handler.Alive) ls.Value.Anchor(); } } #endregion } }