212 lines
5.7 KiB
C#
212 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Cryville.Crtr.Event {
|
|
public class EventBus : StateBase<EventBatch>, IDisposable {
|
|
EventBus prototype = null;
|
|
public ContainerState RootState {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
Dictionary<EventContainer, ContainerState> states
|
|
= new Dictionary<EventContainer, ContainerState>();
|
|
HashSet<EventContainer> activeContainers
|
|
= new HashSet<EventContainer>();
|
|
HashSet<ContainerState> workingStates
|
|
= new HashSet<ContainerState>();
|
|
HashSet<ContainerState> invalidatedStates
|
|
= new HashSet<ContainerState>();
|
|
|
|
public EventBus(ContainerState root, List<EventBatch> b) : base(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<EventContainer, ContainerState>();
|
|
r.activeContainers = new HashSet<EventContainer>();
|
|
r.workingStates = new HashSet<ContainerState>();
|
|
r.invalidatedStates = new HashSet<ContainerState>();
|
|
r.tempEvents = new List<StampedEvent>();
|
|
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 DisposeAll() {
|
|
RootState.DisposeAll();
|
|
}
|
|
|
|
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;
|
|
var state = states[c];
|
|
if (state.Parent != null) EnsureActivity(state.Parent.Container);
|
|
if (RootState.CloneType >= 2) prototype.states[c].CopyTo(RootState.CloneType, state);
|
|
state.Active = true;
|
|
activeContainers.Add(c);
|
|
|
|
if (state.StampedContainer.Coevents == null) return;
|
|
foreach (var cev in state.StampedContainer.Coevents) {
|
|
if (cev.Container == null) continue;
|
|
EnsureActivity(cev.Container);
|
|
states[cev.Container].Handle(cev);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
List<StampedEvent.Temporary> tempEvents = new List<StampedEvent.Temporary>();
|
|
public void PushTempEvent(StampedEvent.Temporary ev) {
|
|
var index = tempEvents.BinarySearch(ev);
|
|
if (index < 0) index = ~index;
|
|
tempEvents.Insert(index, ev);
|
|
}
|
|
|
|
readonly StampedEvent.Temporary _dummyEvent = new StampedEvent.Temporary();
|
|
public void StripTempEvents() {
|
|
_dummyEvent.Time = Time;
|
|
var index = tempEvents.BinarySearch(_dummyEvent);
|
|
if (index < 0) index = ~index;
|
|
for (var i = index - 1; i >= 0; i--) {
|
|
var ev = tempEvents[i];
|
|
tempEvents.RemoveAt(i);
|
|
if (ev.CanDiscard) {
|
|
if (ev.Container != null) {
|
|
states[ev.Container].Discard(ev);
|
|
}
|
|
}
|
|
else {
|
|
ev.Time = Time;
|
|
PushTempEvent(ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void ForwardOnceToTime(double toTime) {
|
|
double time1 = EventId < Events.Count ? Events[EventId].Time : double.PositiveInfinity;
|
|
double time2 = tempEvents.Count > 0 ? tempEvents[0].Time : double.PositiveInfinity;
|
|
double time0 = Math.Min(time1, time2);
|
|
if (time0 <= toTime && time0 != double.PositiveInfinity) {
|
|
Time = time0;
|
|
foreach (var s in workingStates) s.Handle(null);
|
|
ValidateStates();
|
|
if (time1 == time0) {
|
|
var batch = Events[EventId];
|
|
for (var i = 0; i < batch.Count; i++) {
|
|
var ev = batch[i];
|
|
if (ev.Container != null) {
|
|
if (ev.Unstamped is EventContainer) EnsureActivity((EventContainer)ev.Unstamped);
|
|
else EnsureActivity(ev.Container);
|
|
states[ev.Container].Handle(ev);
|
|
}
|
|
else if (ev.Coevents != null) EnsureActivity((EventContainer)ev.Unstamped);
|
|
}
|
|
EventId++;
|
|
}
|
|
if (time2 == time0) {
|
|
while (tempEvents.Count > 0) {
|
|
var ev = tempEvents[0];
|
|
if (ev.Time != time0) break;
|
|
if (ev.Container != null) {
|
|
EnsureActivity(ev.Container);
|
|
states[ev.Container].Handle(ev);
|
|
}
|
|
tempEvents.RemoveAt(0);
|
|
}
|
|
}
|
|
ValidateStates();
|
|
}
|
|
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();
|
|
foreach (var ev in tempEvents) {
|
|
if (ev.Container != null) {
|
|
states[ev.Container].Discard(ev);
|
|
}
|
|
}
|
|
tempEvents.Clear();
|
|
}
|
|
|
|
public void Anchor() {
|
|
if (RootState.Handler.Alive) RootState.Anchor();
|
|
}
|
|
}
|
|
}
|