205 lines
5.3 KiB
C#
205 lines
5.3 KiB
C#
using Cryville.Crtr.Ruleset;
|
|
using Cryville.Crtr.Skin;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Cryville.Crtr.Event {
|
|
public class EventBus : StateBase<EventBatch>, IDisposable {
|
|
public ContainerState RootState {
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
Dictionary<EventContainer, ContainerState> states
|
|
= new();
|
|
HashSet<ContainerState> activeStates
|
|
= new();
|
|
HashSet<ContainerState> invalidatedStates
|
|
= new();
|
|
public int ActiveStateCount { get { return activeStates.Count; } }
|
|
|
|
public EventBus(ContainerState root, List<EventBatch> b) : base(b) {
|
|
RootState = root;
|
|
Expand();
|
|
AttachBus();
|
|
}
|
|
|
|
public EventBus Clone(byte ct, float offsetTime = 0) {
|
|
var r = (EventBus)MemberwiseClone();
|
|
r.states = new Dictionary<EventContainer, ContainerState>();
|
|
r.activeStates = new HashSet<ContainerState>();
|
|
r.invalidatedStates = new HashSet<ContainerState>();
|
|
r.tempEvents = new List<StampedEvent.Temporary>();
|
|
r.Time += offsetTime;
|
|
r.RootState = RootState.Clone(ct);
|
|
r.Expand();
|
|
r.AttachBus();
|
|
foreach (var s in r.states) r.invalidatedStates.Add(s.Value);
|
|
r.ValidateStates();
|
|
return r;
|
|
}
|
|
|
|
public void CopyTo(EventBus dest) {
|
|
base.CopyTo(dest);
|
|
dest.activeStates.Clear();
|
|
dest.invalidatedStates.Clear();
|
|
RootState.CopyTo(dest.RootState);
|
|
dest.ValidateStates();
|
|
}
|
|
|
|
public void Dispose() {
|
|
RootState.Dispose();
|
|
}
|
|
public void DisposeAll() {
|
|
RootState.DisposeAll();
|
|
}
|
|
|
|
public void NotifyActiveChanged(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)
|
|
Expand(c.Value);
|
|
}
|
|
|
|
public void AddState(ContainerState s) {
|
|
states[s.Container] = s;
|
|
s.Bus = this;
|
|
}
|
|
|
|
void AttachBus() {
|
|
foreach (var s in states)
|
|
s.Value.Bus = this;
|
|
}
|
|
|
|
public void AttachSystems(PdtSkin skin, Judge judge) {
|
|
foreach (var s in states)
|
|
s.Value.AttachSystems(skin, judge);
|
|
}
|
|
|
|
List<StampedEvent.Temporary> tempEvents = new();
|
|
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();
|
|
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 activeStates) s.Handle(null);
|
|
ValidateStates();
|
|
if (time1 == time0) {
|
|
var batch = Events[EventId];
|
|
for (var i = 0; i < batch.Count; i++) {
|
|
var ev = batch[i];
|
|
HandleTempEvents(time0, ev.Priority);
|
|
if (ev is StampedEvent.ClipBehind) {
|
|
var cevs = ev.Origin.Coevents;
|
|
if (cevs != null) foreach (var cev in cevs) {
|
|
if (cev.Container == null) continue;
|
|
states[cev.Container].Handle(cev);
|
|
}
|
|
states[(EventContainer)ev.Origin.Unstamped].PhysicalActive = true;
|
|
}
|
|
else if (ev is StampedEvent.ClipAhead) {
|
|
states[(EventContainer)ev.Origin.Unstamped].PhysicalActive = false;
|
|
}
|
|
else if (ev.Container != null) {
|
|
states[ev.Container].Handle(ev);
|
|
}
|
|
}
|
|
EventId++;
|
|
}
|
|
HandleTempEvents(time0);
|
|
}
|
|
else {
|
|
Time = toTime;
|
|
foreach (var s in activeStates) s.Handle(null);
|
|
}
|
|
ValidateStates();
|
|
}
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
void HandleTempEvents(double time, int maxPriority = int.MaxValue) {
|
|
while (tempEvents.Count > 0) {
|
|
var ev = tempEvents[0];
|
|
if (ev.Time != time || ev.Priority >= maxPriority) break;
|
|
if (ev.Container != null) {
|
|
states[ev.Container].Handle(ev);
|
|
}
|
|
tempEvents.RemoveAt(0);
|
|
}
|
|
}
|
|
|
|
private void ValidateStates() {
|
|
foreach (var s in invalidatedStates)
|
|
if (s.Active && !activeStates.Contains(s)) activeStates.Add(s);
|
|
else if (!s.Active && activeStates.Contains(s)) activeStates.Remove(s);
|
|
invalidatedStates.Clear();
|
|
}
|
|
|
|
public void BroadcastPreInit() {
|
|
RootState.BroadcastPreInit();
|
|
}
|
|
public void BroadcastPostInit() {
|
|
RootState.BroadcastPostInit();
|
|
}
|
|
|
|
public void EndPreGraphicalUpdate() {
|
|
RootState.EndPreGraphicalUpdate();
|
|
ClearTempEvents();
|
|
}
|
|
public void EndGraphicalUpdate() {
|
|
RootState.EndGraphicalUpdate();
|
|
ClearTempEvents();
|
|
}
|
|
|
|
void ClearTempEvents() {
|
|
foreach (var ev in tempEvents) {
|
|
if (ev.Container != null) {
|
|
states[ev.Container].Discard(ev);
|
|
}
|
|
}
|
|
tempEvents.Clear();
|
|
}
|
|
|
|
public void PreAnchor() {
|
|
if (RootState.Handler.Alive) RootState.PreAnchor();
|
|
}
|
|
|
|
public void Anchor() {
|
|
if (RootState.Handler.Alive) RootState.Anchor();
|
|
}
|
|
}
|
|
}
|