using System; using System.Collections.Generic; namespace Cryville.Crtr.Event { public class EventBus : StateBase, IDisposable { EventBus prototype = null; public ContainerState RootState { get; private set; } Dictionary states = new Dictionary(); List activeContainers = new List(); HashSet workingStates = new HashSet(); HashSet invalidatedStates = new HashSet(); public EventBus(Chart c, ContainerState root, List b) : base(c, b) { RootState = root; Expand(); AttachBus(); RootState.Working = true; } public EventBus Clone(byte ct, float offsetTime = 0) { var r = (EventBus)MemberwiseClone(); r.prototype = this; r.states = new Dictionary(); r.activeContainers = new List(); r.workingStates = new HashSet(); r.invalidatedStates = new HashSet(); r.Time += offsetTime; r.RootState = RootState.Clone(ct); r.RootState.StartUpdate(); r.Expand(); r.AttachBus(); foreach (var s in r.states) r.invalidatedStates.Add(s.Value); r.ValidateStates(); return r; } public void CopyTo(byte ct, EventBus dest) { base.CopyTo(dest); dest.workingStates.Clear(); dest.invalidatedStates.Clear(); RootState.CopyTo(ct, dest.RootState); if (ct >= 2) { dest.activeContainers.Clear(); foreach (var c in activeContainers) { if (states[c].Working) { states[c].CopyTo(ct, dest.states[c]); dest.activeContainers.Add(c); } } } dest.ValidateStates(); } public void Dispose() { RootState.Dispose(); } public void NotifyWorkingChanged(ContainerState state) { if (!invalidatedStates.Contains(state)) invalidatedStates.Add(state); } void Expand(ContainerState s = null) { if (s == null) { states.Clear(); s = RootState; } AddState(s); foreach (var c in s.Children.Values) Expand(c); } public void AddState(ContainerState s) { states[s.Container] = s; s.Bus = this; } void EnsureActivity(EventContainer c) { if (activeContainers.Contains(c)) return; if (RootState.CloneType >= 2) prototype.states[c].CopyTo(RootState.CloneType, states[c]); activeContainers.Add(c); } void AttachBus() { foreach (var s in states.Values) s.Bus = this; } public void AttachSystems(PdtSkin skin, Judge judge) { foreach (var s in states.Values) s.AttachSystems(skin, judge); } readonly List patch = new List(); public void IssuePatch(IEnumerable l) { patch.AddRange(l); } public void DoPatch() { foreach (var ev in patch) { var batch = new EventBatch(ev.Time); var batchIndex = events.BinarySearch(batch); if (batchIndex >= 0) batch = events[batchIndex]; else events.Insert(~batchIndex, batch); batch.Add(ev); } patch.Clear(); } public override void ForwardOnceToTime(float toTime, Action callback = null) { if (EventId < events.Count && events[EventId].Time <= toTime) { Time = events[EventId].Time; var batch = events[EventId]; foreach (var s in workingStates) s.Handle(null); ValidateStates(); for (var i = 0; i < batch.Count; i++) { var ev = batch[i]; if (ev.Container != null) { EnsureActivity(ev.Container); states[ev.Container].Handle(ev); } if (ev.Unstamped is EventContainer) { if (ev.Container != null) EnsureActivity((EventContainer)ev.Unstamped); } } ValidateStates(); EventId++; } else { Time = toTime; foreach (var s in workingStates) s.Handle(null); ValidateStates(); } } private void ValidateStates() { foreach (var s in invalidatedStates) if (s.Working && !workingStates.Contains(s)) workingStates.Add(s); else if (!s.Working && workingStates.Contains(s)) workingStates.Remove(s); invalidatedStates.Clear(); } public void BroadcastPreInit() { RootState.BroadcastPreInit(); } public void BroadcastPostInit() { RootState.BroadcastPostInit(); } public void BroadcastEndUpdate() { RootState.BroadcastEndUpdate(); } public void Anchor() { RootState.Anchor(); } } }