//#define DISABLE_CACHE using Cryville.Common; using System; using System.Collections.Generic; using UnityEngine; namespace Cryville.Crtr.Event { public class ContainerState { public EventBus Bus; public EventContainer Container; public ContainerState Parent = null; public ushort Depth; public Dictionary Children = new Dictionary(); HashSet WorkingChildren = new HashSet(); HashSet InvalidatedChildren = new HashSet(); public Dictionary> TypedChildren = new Dictionary>(); public ContainerState GetChild(int index, Type handlerType) { return TypedChildren[handlerType][index]; } public ContainerState GetChild(EventContainer ev) { /*if (!Children.ContainsKey(ev)) { Children[ev] = prototype.FetchChildClone(ev, CloneType); }*/ return Children[ev]; } /*ContainerState FetchChildClone(EventContainer ev, byte ct) { return Children[ev].Clone(ct); }*/ void NotifyWorkingChanged(EventContainer key) { InvalidatedChildren.Add(key); } void ValidateChildren() { foreach (var cev in InvalidatedChildren) if (Children[cev].Working && !WorkingChildren.Contains(cev)) WorkingChildren.Add(cev); else if (!Children[cev].Working && WorkingChildren.Contains(cev)) WorkingChildren.Remove(cev); InvalidatedChildren.Clear(); } private bool m_Working; public bool Working { get { return m_Working; } set { m_Working = value; if (Parent != null) Parent.NotifyWorkingChanged(Container); Bus.NotifyWorkingChanged(this); } } public byte CloneType; private ContainerState rootPrototype = null; private ContainerState prototype = null; // public SkinManager skinManager; public SkinContainer skinContainer; public Judge judge; public ContainerHandler Handler { get; private set; } public float Time { get { return Bus.Time; } } readonly RMVPool RMVPool = new RMVPool(); protected Dictionary PlayingMotions = new Dictionary(); protected Dictionary Values = new Dictionary(); protected Dictionary CachedValues = new Dictionary(); protected Dictionary CachedValueStates = new Dictionary(); /// /// Gets a motion value. /// /// The motion name. /// Returns a cloned motion value instead. /// A motion value. RealtimeMotionValue GetMotionValue(MotionName name, bool clone = false) { RealtimeMotionValue value; if (!Values.TryGetValue(name, out value)) { value = new RealtimeMotionValue().Init(Parent == null ? ChartPlayer.motionRegistry[name.MainName].GlobalInitValue : ChartPlayer.motionRegistry[name.MainName].InitValue ); Values.Add(name, value); } if (clone) return value.Clone(); return value; } void InvalidateMotion(MotionName name) { // if (CachedValues.ContainsKey(name)) CachedValueStates[name] = false; foreach (var c in Children) c.Value.InvalidateMotion(name); } public ContainerState(Chart c, EventContainer _ev, ContainerState parent = null) { Container = _ev; if (parent != null) { AddChild(_ev, this, parent); Parent = parent; } foreach (var m in ChartPlayer.motionRegistry) Values.Add(new MotionName(m.Key), new RealtimeMotionValue().Init(Parent == null ? m.Value.GlobalInitValue : m.Value.InitValue)); //skinManager = new SkinManager(skin, this); //events.Sort((a, b) => a.Time.CompareTo(b.Time)); } static void AddChild(EventContainer c, ContainerState s, ContainerState target) { target.Children.Add(c, s); Type t = c.GetType(); if (!target.TypedChildren.ContainsKey(t)) target.TypedChildren.Add(t, new List()); target.TypedChildren[t].Add(s); } public ContainerState Clone(byte ct) { /*if (prototype != null) throw new InvalidOperationException();*/ var r = (ContainerState)MemberwiseClone(); var mvs = new Dictionary(Values.Count); foreach (var mv in Values) { mvs.Add(mv.Key, mv.Value.Clone()); } r.Values = mvs; var cvs = new Dictionary(CachedValues.Count); foreach (var cv in CachedValues) { cvs.Add(cv.Key, cv.Value.Clone()); } r.CachedValues = cvs; var cvss = new Dictionary(CachedValueStates.Count); foreach (var cv in CachedValueStates) { cvss.Add(cv.Key, cv.Value); } r.CachedValueStates = cvss; r.Children = new Dictionary(); foreach (var child in Children) { // if (!child.Value.Working && ct != 1) continue; var cc = child.Value.Clone(ct); cc.Parent = r; AddChild(child.Key, cc, r); } var pms = new Dictionary(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.prototype = this; if (prototype == null) r.rootPrototype = this; else r.rootPrototype = rootPrototype; r.CloneType = ct; return r; } public void CopyTo(byte ct, ContainerState dest) { dest.Working = Working; 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()); } // dest.CachedValues.Clear(); foreach (var cv in CachedValues) { Vector dv; if(dest.CachedValues.TryGetValue(cv.Key, out dv)) cv.Value.CopyTo(dv); else dest.CachedValues.Add(cv.Key, cv.Value.Clone()); } foreach (var cvs in CachedValueStates) dest.CachedValueStates[cvs.Key] = cvs.Value; if (ct != 1) foreach (var cev in WorkingChildren) Children[cev].CopyTo(ct, dest.Children[cev]); else foreach (var child in Children) child.Value.CopyTo(ct, dest.Children[child.Key]); ValidateChildren(); RMVPool.ReturnAll(); 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 (Handler != null) Handler.Dispose(); foreach (var s in Children) s.Value.Dispose(); RMVPool.ReturnAll(); } public void AttachHandler(ContainerHandler h) { if (Handler != null) throw new InvalidOperationException(); Handler = h; h.cs = this; } public void AttachSystems(PdtSkin skin, Judge judge) { // skinManager = new SkinManager(skin); skinContainer = new SkinContainer(skin); this.judge = judge; } public T GetRawValue(MotionName key) where T : Vector { Vector tr; if (!CachedValues.TryGetValue(key, out tr)) { tr = (Vector)ReflectionHelper.InvokeEmptyConstructor(typeof(T)); CachedValues.Add(key, tr); CachedValueStates[key] = false; } T r = (T)tr; #if !DISABLE_CACHE if (CachedValueStates[key]) return r; #endif float reltime = 0; if (rootPrototype != null) reltime = Time - rootPrototype.Time; GetMotionValue(key).GetValue(reltime, ref r); if (Parent != null) r.ApplyFrom(Parent.GetRawValue(key)); #if !DISABLE_CACHE CachedValueStates[key] = true; #endif return r; } static readonly MotionName n_dir = new MotionName("dir"); public Vector3 Direction { get { Vec3 r = GetRawValue(n_dir); return r.ToVector3(); } } static readonly MotionName n_normal = new MotionName("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 MotionName n_pt = new MotionName("pt"); public Vector2 ScreenPoint { get { var mv = GetRawValue(n_pt); return mv.ToVector2(ChartPlayer.hitRect); } } static readonly MotionName n_visible = new MotionName("visible"); public bool Visible { get { return GetRawValue(n_visible).Value % 2 >= 1; } } static readonly MotionName n_sv = new MotionName("sv"); static readonly MotionName n_svm = new MotionName("svm"); public float ScrollVelocity { get { return GetRawValue(n_sv).ToFloat(ChartPlayer.hitRect) * GetRawValue(n_svm).Value; } } static readonly MotionName n_dist = new MotionName("dist"); public float Distance { get { var mv = GetRawValue(n_dist); return mv.ToFloat(ChartPlayer.hitRect); } } static readonly MotionName n_corner = new MotionName("corner"); public bool Corner { get { return GetRawValue(n_corner).Value % 2 >= 1; } } static readonly MotionName n_ctrl0 = new MotionName("ctrl0"); static readonly MotionName n_ctrl1 = new MotionName("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 MotionName n_track = new MotionName("track"); public float Track { get { return GetRawValue(n_track).Value; } } bool breakflag = false; public void Break() { Handler.EndUpdate(this); breakflag = true; Working = false; } public void Handle(StampedEvent ev, Action callback = null) { if (breakflag) { // Time = toTime; return; } if (ev != null) { bool flag = false; if (ev.Unstamped is Chart.Motion) { var tev = (Chart.Motion)ev.Unstamped; // tev._apply(Values); var mv = RMVPool.Rent(tev.Name); GetMotionValue(tev.Name).CopyTo(mv); PlayingMotions.Add(ev, mv); Callback(ev, callback); // UpdateMotions(); if (!ev.Unstamped.IsLong) PlayingMotions.Remove(ev); } else if (ev.Unstamped is EventContainer) { var cev = (EventContainer)ev.Unstamped; var ccs = GetChild(cev); ccs.Working = true; ccs.StartUpdate(); UpdateMotions(); if (!ev.Unstamped.IsLong) { ccs.Working = false; ccs.BroadcastEndUpdate(); if (CloneType == 1) ccs.Dispose(); } } else if (ev.Unstamped is InstantEvent) { var tev = (InstantEvent)ev.Unstamped; if (tev.IsRelease) { var nev = tev.Original; if (nev is Chart.Motion) { // var tnev = (Chart.Motion)nev; Callback(ev, callback); // UpdateMotions(); PlayingMotions.Remove(ev.Origin); } else if (nev is EventContainer) { var cev = (EventContainer)ev.Origin.Unstamped; var ccs = GetChild(cev); UpdateMotions(); ccs.Working = false; ccs.BroadcastEndUpdate(); if (CloneType == 1) ccs.Dispose(); } } } if (ev.Unstamped == null) { Callback(ev, callback); flag = true; } else if (ev.Unstamped.Priority >= 0) { Callback(ev, callback); flag = true; } if (!flag) Callback(null, callback); return; } // Time = toTime; Callback(null, callback); } void Callback(StampedEvent ev, Action callback) { UpdateMotions(); if (callback != null) callback(ev); if (ev == null || ev.Unstamped != null) Handler.Update(this, ev); else Handler.ExUpdate(this, ev); /*if (CloneType == 1) { if (ev == null || ev.Event != null) Handler.Forward(ev); else Handler.ExUpdate(CloneType, ev); } else if (CloneType == 0) { if (ev == null || ev.Event != null) Handler.Update(ev); else Handler.ExUpdate(CloneType, ev); } else if (CloneType == 2) { // TODO Do nothing atm } else if (CloneType >= 16) { if (ev == null || ev.Event != null) Handler.PreUpdate(CloneType, ev); else Handler.ExUpdate(CloneType, ev); }*/ foreach (var m in PlayingMotions) Handler.MotionUpdate(CloneType, (Chart.Motion)m.Key.Unstamped); } 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/*, true*/); InvalidateMotion(tev.Name); if (m.Key.Duration == 0) { if (tev.RelativeNode != null) { value.SetRelativeNode(tev.RelativeNode); } else { value.AbsoluteValue.ReplaceFrom(tev.AbsoluteValue); } } else { var scaledTime = (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] = value; } } public void BroadcastInit() { Handler.PreInit(); Handler.Init(); foreach (var s in Children) { s.Value.BroadcastInit(); } Handler.PostInit(); } public void StartUpdate() { Handler.StartUpdate(this); } public void BroadcastEndUpdate() { Handler.EndUpdate(this); foreach (var ls in Children.Values) { if (ls.Working) ls.BroadcastEndUpdate(); } } public void Anchor() { Handler.Anchor(); foreach (var ls in Children.Values) { if (ls.Handler.Alive) ls.Anchor(); } } } }