137 lines
3.7 KiB
C#
137 lines
3.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace Cryville.Crtr.Event {
|
|
public class EventBatcher : StateBase<ChartEvent> {
|
|
public EventBus Bus {
|
|
get;
|
|
private set;
|
|
}
|
|
ContainerState RootState;
|
|
/// <summary>
|
|
/// event => the container state that handles the event
|
|
/// </summary>
|
|
readonly Dictionary<ChartEvent, ContainerState> table
|
|
= new Dictionary<ChartEvent, ContainerState>();
|
|
public List<StampedEvent> stampedEvents = new List<StampedEvent>();
|
|
readonly List<EventBatch> batches = new List<EventBatch>();
|
|
|
|
double beat;
|
|
float tempo;
|
|
|
|
public EventBatcher(Chart c) : base(c, new List<ChartEvent>()) {
|
|
beat = chart.BeatPosition;
|
|
tempo = (float)c.sigs[0].tempo;
|
|
events.Add(c);
|
|
events.Add(c.ReleaseEvent);
|
|
AddEventContainer(c);
|
|
events.Sort((a, b) => a.BeatPosition.CompareTo(b.BeatPosition));
|
|
}
|
|
|
|
void AddEventContainer(EventContainer c, ContainerState parent = null) {
|
|
var cs = new ContainerState(chart, c, parent);
|
|
if (parent == null) {
|
|
cs.Depth = 0;
|
|
RootState = cs;
|
|
}
|
|
else {
|
|
cs.Depth = (ushort)(parent.Depth + 1);
|
|
}
|
|
foreach (var ev in c.Events) {
|
|
if (ev.time == null) {
|
|
ev.time = c.time;
|
|
if (ev is EventContainer)
|
|
ev.endtime = c.endtime;
|
|
}
|
|
if (ev.IsLong) {
|
|
events.Add(ev.ReleaseEvent);
|
|
table.Add(ev.ReleaseEvent, cs);
|
|
}
|
|
events.Add(ev);
|
|
table.Add(ev, cs);
|
|
if (ev is EventContainer)
|
|
AddEventContainer((EventContainer)ev, cs);
|
|
}
|
|
}
|
|
|
|
public override void ForwardOnceToTime(double toTime) {
|
|
double toBeat = Math.Round(beat + (toTime - Time) * tempo / 60f, 6);
|
|
if (EventId >= events.Count)
|
|
goto return_ahead;
|
|
double ebeat = events[EventId].BeatPosition;
|
|
double etime = Math.Round((ebeat - beat) / tempo * 60f + Time, 6);
|
|
if (etime > toTime)
|
|
goto return_ahead;
|
|
var batch = GetEventBatch();
|
|
Time = etime;
|
|
beat = ebeat;
|
|
foreach (var ev in batch) {
|
|
EventContainer con = null;
|
|
if (table.ContainsKey(ev)) con = table[ev].Container;
|
|
var sev = new StampedEvent() {
|
|
Time = etime,
|
|
Unstamped = ev,
|
|
Container = con
|
|
};
|
|
if (ev is InstantEvent) {
|
|
var tev = (InstantEvent)ev;
|
|
var pev = stampedEvents.First(tpev => tpev.Unstamped == tev.Original);
|
|
pev.Subevents.Add(sev);
|
|
sev.Origin = pev;
|
|
}
|
|
stampedEvents.Add(sev);
|
|
if (ev is Chart.Signature) {
|
|
var tev = (Chart.Signature)ev;
|
|
if (tev.tempo != null) tempo = (float)tev.tempo;
|
|
}
|
|
EventId++;
|
|
}
|
|
return;
|
|
return_ahead:
|
|
Time = toTime;
|
|
beat = toBeat;
|
|
}
|
|
|
|
IOrderedEnumerable<ChartEvent> GetEventBatch() {
|
|
float cbeat = events[EventId].BeatPosition;
|
|
int b = EventId;
|
|
while (Mathf.Approximately(events[b].BeatPosition, cbeat)) {
|
|
b--;
|
|
if (b == -1) break;
|
|
}
|
|
int a = EventId;
|
|
while (Mathf.Approximately(events[a].BeatPosition, cbeat)) {
|
|
a++;
|
|
if (a == events.Count) break;
|
|
}
|
|
return from ev in events.GetRange(b + 1, a - b - 1) orderby ev.Priority select ev;
|
|
}
|
|
|
|
public EventBus Batch() {
|
|
stampedEvents.Sort((a, b) => {
|
|
int u = a.CompareTo(b);
|
|
if (u != 0) return u;
|
|
if (a.Unstamped != null && b.Unstamped != null)
|
|
if (table.ContainsKey(a.Unstamped) && table.ContainsKey(b.Unstamped)) {
|
|
u = table[a.Unstamped].Depth.CompareTo(table[b.Unstamped].Depth);
|
|
if (u != 0) return u;
|
|
}
|
|
return a.GetHashCode().CompareTo(b.GetHashCode());
|
|
});
|
|
var cb = new EventBatch(stampedEvents[0].Time);
|
|
foreach (var ev in stampedEvents) {
|
|
if (ev.Time != cb.Time) {
|
|
batches.Add(cb);
|
|
cb = new EventBatch(ev.Time);
|
|
}
|
|
cb.Enqueue(ev);
|
|
}
|
|
batches.Add(cb);
|
|
Bus = new EventBus(chart, RootState, batches);
|
|
return Bus;
|
|
}
|
|
}
|
|
}
|