Add project files.
This commit is contained in:
137
Assets/Cryville/Crtr/Event/ContainerHandler.cs
Normal file
137
Assets/Cryville/Crtr/Event/ContainerHandler.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using Cryville.Crtr.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Cryville.Crtr.Event {
|
||||
public abstract class ContainerHandler : IDisposable {
|
||||
/// <summary>
|
||||
/// Prehandling <see cref="ContainerState"/>, prehandling the events.
|
||||
/// </summary>
|
||||
public ContainerState ps;
|
||||
|
||||
/// <summary>
|
||||
/// Backward <see cref="ContainerState"/>, disposing events at the backward clipping plane, firing anchor state and temporary state.
|
||||
/// </summary>
|
||||
public ContainerState bs;
|
||||
|
||||
/// <summary>
|
||||
/// Current <see cref="ContainerState"/>, handling events occuring at the current time.
|
||||
/// </summary>
|
||||
public ContainerState cs;
|
||||
|
||||
/// <summary>
|
||||
/// Anchor <see cref="ContainerState"/>, computing the start position of the temporary state.
|
||||
/// </summary>
|
||||
public ContainerState ns;
|
||||
|
||||
/// <summary>
|
||||
/// Temporary <see cref="ContainerState"/>, rendering events between the clipping planes.
|
||||
/// </summary>
|
||||
public ContainerState ts;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GameObject"/> group, the <see cref="Transform"/> containing all the generated elements in the <see cref="ContainerHandler"/>.
|
||||
/// </summary>
|
||||
public Transform gogroup;
|
||||
|
||||
public readonly Dictionary<string, Anchor> Anchors = new Dictionary<string, Anchor>();
|
||||
public Transform a_head;
|
||||
public Transform a_tail;
|
||||
public Vector3 Position {
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
public Quaternion Rotation {
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
public bool Alive {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public bool Awoken {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public bool Disposed {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public EventContainer Container {
|
||||
get { return cs.Container; }
|
||||
}
|
||||
|
||||
public ContainerHandler() { }
|
||||
public abstract string TypeName {
|
||||
get;
|
||||
}
|
||||
public virtual void PreInit() {
|
||||
gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString()).transform;
|
||||
if (cs.Parent != null)
|
||||
gogroup.SetParent(cs.Parent.Handler.gogroup, false);
|
||||
a_head = new GameObject("::head").transform;
|
||||
a_head.SetParent(gogroup, false);
|
||||
Anchors.Add("head", new Anchor() { Transform = a_head });
|
||||
a_tail = new GameObject("::tail").transform;
|
||||
a_tail.SetParent(gogroup, false);
|
||||
Anchors.Add("tail", new Anchor() { Transform = a_tail });
|
||||
}
|
||||
/// <summary>
|
||||
/// Called upon initialization of <see cref="cs" />.
|
||||
/// </summary>
|
||||
public virtual void Init() {
|
||||
cs.skinContainer.MatchStatic(cs);
|
||||
foreach (var i in gogroup.GetComponentsInChildren<SkinComponent>())
|
||||
i.Init();
|
||||
}
|
||||
public virtual void PostInit() {
|
||||
gogroup.gameObject.SetActive(false);
|
||||
}
|
||||
public virtual void Dispose() {
|
||||
if (Disposed) return;
|
||||
Disposed = true;
|
||||
if (gogroup)
|
||||
GameObject.Destroy(gogroup.gameObject);
|
||||
// gogroup.gameObject.SetActive(false);
|
||||
Alive = false;
|
||||
}
|
||||
protected virtual void PreAwake(ContainerState s) {
|
||||
if (gogroup) gogroup.gameObject.SetActive(true);
|
||||
Awoken = true; Alive = true;
|
||||
OpenAnchor("head");
|
||||
}
|
||||
protected virtual void Awake(ContainerState s) {
|
||||
CloseAnchor("head");
|
||||
}
|
||||
protected virtual void GetPosition(ContainerState s) { }
|
||||
public virtual void StartUpdate(ContainerState s) {
|
||||
if (s.CloneType >= 2 && s.CloneType < 16) {
|
||||
PreAwake(s);
|
||||
Awake(s);
|
||||
}
|
||||
}
|
||||
public virtual void Update(ContainerState s, StampedEvent ev) {
|
||||
bool flag = !Awoken && s.CloneType >= 2 && s.CloneType < 16;
|
||||
if (flag) PreAwake(s);
|
||||
if (Awoken && s.CloneType <= 2) if (gogroup) cs.skinContainer.MatchDynamic(s);
|
||||
if (flag) Awake(s);
|
||||
}
|
||||
public virtual void ExUpdate(ContainerState s, StampedEvent ev) { }
|
||||
public virtual void MotionUpdate(byte ct, Chart.Motion ev) { }
|
||||
public virtual void EndUpdate(ContainerState s) {
|
||||
if (s.CloneType < 16) {
|
||||
Awoken = false;
|
||||
if (gogroup && s.CloneType <= 2) cs.skinContainer.MatchDynamic(s);
|
||||
}
|
||||
}
|
||||
public virtual void Anchor() { }
|
||||
protected void OpenAnchor(string name) {
|
||||
if (Anchors.ContainsKey(name)) Anchors[name].Open();
|
||||
}
|
||||
protected void CloseAnchor(string name) {
|
||||
if (Anchors.ContainsKey(name)) Anchors[name].Close();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/ContainerHandler.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/ContainerHandler.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da65ca35eb403a94ab9a1e07f7b3100c
|
||||
timeCreated: 1617788981
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
485
Assets/Cryville/Crtr/Event/ContainerState.cs
Normal file
485
Assets/Cryville/Crtr/Event/ContainerState.cs
Normal file
@@ -0,0 +1,485 @@
|
||||
//#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<EventContainer, ContainerState> Children
|
||||
= new Dictionary<EventContainer, ContainerState>();
|
||||
HashSet<EventContainer> WorkingChildren
|
||||
= new HashSet<EventContainer>();
|
||||
HashSet<EventContainer> InvalidatedChildren
|
||||
= new HashSet<EventContainer>();
|
||||
public Dictionary<Type, List<ContainerState>> TypedChildren
|
||||
= new Dictionary<Type, List<ContainerState>>();
|
||||
|
||||
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<StampedEvent, RealtimeMotionValue> PlayingMotions = new Dictionary<StampedEvent, RealtimeMotionValue>();
|
||||
protected Dictionary<MotionName, RealtimeMotionValue> Values = new Dictionary<MotionName, RealtimeMotionValue>();
|
||||
protected Dictionary<MotionName, Vector> CachedValues = new Dictionary<MotionName, Vector>();
|
||||
protected Dictionary<MotionName, bool> CachedValueStates = new Dictionary<MotionName, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a motion value.
|
||||
/// </summary>
|
||||
/// <param name="name">The motion name.</param>
|
||||
/// <param name="clone">Returns a cloned motion value instead.</param>
|
||||
/// <returns>A motion value.</returns>
|
||||
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<ContainerState>());
|
||||
target.TypedChildren[t].Add(s);
|
||||
}
|
||||
|
||||
public ContainerState Clone(byte ct) {
|
||||
/*if (prototype != null)
|
||||
throw new InvalidOperationException();*/
|
||||
|
||||
var r = (ContainerState)MemberwiseClone();
|
||||
|
||||
var mvs = new Dictionary<MotionName, RealtimeMotionValue>(Values.Count);
|
||||
foreach (var mv in Values) {
|
||||
mvs.Add(mv.Key, mv.Value.Clone());
|
||||
}
|
||||
r.Values = mvs;
|
||||
|
||||
var cvs = new Dictionary<MotionName, Vector>(CachedValues.Count);
|
||||
foreach (var cv in CachedValues) {
|
||||
cvs.Add(cv.Key, cv.Value.Clone());
|
||||
}
|
||||
r.CachedValues = cvs;
|
||||
|
||||
var cvss = new Dictionary<MotionName, bool>(CachedValueStates.Count);
|
||||
foreach (var cv in CachedValueStates) {
|
||||
cvss.Add(cv.Key, cv.Value);
|
||||
}
|
||||
r.CachedValueStates = cvss;
|
||||
|
||||
r.Children = new Dictionary<EventContainer, ContainerState>();
|
||||
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<StampedEvent, RealtimeMotionValue>(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<T>(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<T>(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<Vec3>(n_dir);
|
||||
return r.ToVector3();
|
||||
}
|
||||
}
|
||||
|
||||
static readonly MotionName n_normal = new MotionName("normal");
|
||||
public Vector3 Normal {
|
||||
get {
|
||||
Vec3 r = GetRawValue<Vec3>(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<VecPt>(n_pt);
|
||||
return mv.ToVector2(ChartPlayer.hitRect);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly MotionName n_visible = new MotionName("visible");
|
||||
public bool Visible {
|
||||
get {
|
||||
return GetRawValue<VecI1>(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<VecPtComp>(n_sv).ToFloat(ChartPlayer.hitRect)
|
||||
* GetRawValue<Vec1m>(n_svm).Value;
|
||||
}
|
||||
}
|
||||
|
||||
static readonly MotionName n_dist = new MotionName("dist");
|
||||
public float Distance {
|
||||
get {
|
||||
var mv = GetRawValue<VecPtComp>(n_dist);
|
||||
return mv.ToFloat(ChartPlayer.hitRect);
|
||||
}
|
||||
}
|
||||
|
||||
static readonly MotionName n_corner = new MotionName("corner");
|
||||
public bool Corner {
|
||||
get {
|
||||
return GetRawValue<VecI1>(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<VecCtrl>(alt1 ? n_ctrl1 : n_ctrl0);
|
||||
if (alt1 && mv.IsZero()) {
|
||||
mv = GetRawValue<VecCtrl>(n_ctrl0);
|
||||
}
|
||||
return mv.ToVector3(ChartPlayer.hitRect, deltaz);
|
||||
}
|
||||
|
||||
static readonly MotionName n_track = new MotionName("track");
|
||||
public float Track {
|
||||
get {
|
||||
return GetRawValue<Vec1>(n_track).Value;
|
||||
}
|
||||
}
|
||||
|
||||
bool breakflag = false;
|
||||
|
||||
public void Break() {
|
||||
Handler.EndUpdate(this);
|
||||
breakflag = true;
|
||||
Working = false;
|
||||
}
|
||||
|
||||
public void Handle(StampedEvent ev, Action<StampedEvent> 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<StampedEvent> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/ContainerState.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/ContainerState.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2ebe22dbedf60c4b96dd6ae834a740f
|
||||
timeCreated: 1617701716
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
47
Assets/Cryville/Crtr/Event/EventBatch.cs
Normal file
47
Assets/Cryville/Crtr/Event/EventBatch.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Cryville.Crtr.Event {
|
||||
public class EventBatch : IComparable<EventBatch>, IEnumerable<StampedEvent> {
|
||||
public float Time {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
readonly List<StampedEvent> queue = new List<StampedEvent>();
|
||||
public int Count {
|
||||
get { return queue.Count; }
|
||||
}
|
||||
|
||||
public EventBatch(float time) {
|
||||
Time = time;
|
||||
}
|
||||
|
||||
public StampedEvent this[int index] {
|
||||
get { return queue[index]; }
|
||||
}
|
||||
|
||||
public void Add(StampedEvent ev) {
|
||||
Enqueue(ev);
|
||||
}
|
||||
|
||||
public void Enqueue(StampedEvent ev) {
|
||||
int i = queue.BinarySearch(ev);
|
||||
if (i < 0) queue.Insert(~i, ev);
|
||||
}
|
||||
|
||||
public int CompareTo(EventBatch other) {
|
||||
return this.Time.CompareTo(other.Time);
|
||||
}
|
||||
|
||||
public IEnumerator<StampedEvent> GetEnumerator() {
|
||||
return queue.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/EventBatch.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/EventBatch.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 532772ba68ebf6d49a83a49e9e13cbdd
|
||||
timeCreated: 1617673011
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
147
Assets/Cryville/Crtr/Event/EventBatcher.cs
Normal file
147
Assets/Cryville/Crtr/Event/EventBatcher.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
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>();
|
||||
|
||||
float 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);
|
||||
/*if (ev is Chart.Note) {
|
||||
events.Add(ev.AttackEvent);
|
||||
}*/
|
||||
}
|
||||
events.Add(ev);
|
||||
table.Add(ev, cs);
|
||||
if (ev is EventContainer)
|
||||
AddEventContainer((EventContainer)ev, cs);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ForwardOnceToTime(float toTime, Action<ChartEvent> callback) {
|
||||
float toBeat = (float)Math.Round(beat + (toTime - Time) * tempo / 60f, 6);
|
||||
if (EventId >= events.Count)
|
||||
goto return_ahead;
|
||||
float ebeat = events[EventId].BeatPosition;
|
||||
float etime = (float)Math.Round((ebeat - beat) / tempo * 60f + Time, 6);
|
||||
if (etime > toTime)
|
||||
goto return_ahead;
|
||||
var batch = GetEventBatch();
|
||||
Time = etime;
|
||||
beat = ebeat;
|
||||
bool flag = false;
|
||||
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.Priority >= 0) {
|
||||
if (callback != null) callback(ev);
|
||||
flag = true;
|
||||
}
|
||||
if (ev is Chart.Signature) {
|
||||
var tev = (Chart.Signature)ev;
|
||||
if (tev.tempo != null) tempo = (float)tev.tempo;
|
||||
}
|
||||
EventId++;
|
||||
}
|
||||
if (callback != null && !flag) callback(batch.First());
|
||||
return;
|
||||
return_ahead:
|
||||
Time = toTime;
|
||||
beat = toBeat;
|
||||
// foreach (var c in Children) c.ForwardToTime(Time);
|
||||
if (callback != null) callback(null);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/EventBatcher.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/EventBatcher.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 494728f9d5dcbd443b5e109420c02d2a
|
||||
timeCreated: 1617663907
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
177
Assets/Cryville/Crtr/Event/EventBus.cs
Normal file
177
Assets/Cryville/Crtr/Event/EventBus.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
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>();
|
||||
List<EventContainer> activeContainers
|
||||
= new List<EventContainer>();
|
||||
HashSet<ContainerState> workingStates
|
||||
= new HashSet<ContainerState>();
|
||||
HashSet<ContainerState> invalidatedStates
|
||||
= new HashSet<ContainerState>();
|
||||
|
||||
public EventBus(Chart c, ContainerState root, List<EventBatch> 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<EventContainer, ContainerState>();
|
||||
r.activeContainers = new List<EventContainer>();
|
||||
r.workingStates = new HashSet<ContainerState>();
|
||||
r.invalidatedStates = new HashSet<ContainerState>();
|
||||
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(byte ct, EventBus dest) {
|
||||
base.CopyTo(dest);
|
||||
// dest.states.Clear();
|
||||
dest.workingStates.Clear();
|
||||
dest.invalidatedStates.Clear();
|
||||
RootState.CopyTo(ct, dest.RootState);
|
||||
// foreach (var s in dest.states) dest.invalidatedStates.Add(s.Value);
|
||||
dest.ValidateStates();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
RootState.Dispose();
|
||||
}
|
||||
|
||||
public void NotifyWorkingChanged(ContainerState 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;
|
||||
}
|
||||
|
||||
/*
|
||||
public void AddChildState(EventContainer p, EventContainer c) {
|
||||
if (!states.ContainsKey(p)) AddChildState(prototype.states[p].Parent.Container, p);
|
||||
if (!states.ContainsKey(c)) AddState(states[p].GetChild(c));
|
||||
// if (prototype != null) prototype.states[c].CopyTo(RootState.CloneType, states[c]);
|
||||
}*/
|
||||
|
||||
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<StampedEvent> patch = new List<StampedEvent>();
|
||||
public void IssuePatch(IEnumerable<StampedEvent> 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<EventBatch> 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) {
|
||||
/* if (prototype != null && !states.ContainsKey(ev.Container))
|
||||
AddChildState(prototype.states[ev.Container].Parent.Container, ev.Container); */
|
||||
// TODO
|
||||
// if (prototype != null) prototype.states[ev.Container].CopyTo(RootState.CloneType, states[ev.Container]);
|
||||
EnsureActivity(ev.Container);
|
||||
states[ev.Container].Handle(ev);
|
||||
}
|
||||
if (ev.Unstamped is EventContainer) {
|
||||
if (ev.Container != null) EnsureActivity((EventContainer)ev.Unstamped);
|
||||
// AddChildState(ev.Container, (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 BroadcastInit() {
|
||||
RootState.BroadcastInit();
|
||||
}
|
||||
|
||||
public void BroadcastEndUpdate() {
|
||||
RootState.BroadcastEndUpdate();
|
||||
}
|
||||
|
||||
public void Anchor() {
|
||||
RootState.Anchor();
|
||||
}
|
||||
}
|
||||
}
|
12
Assets/Cryville/Crtr/Event/EventBus.cs.meta
Normal file
12
Assets/Cryville/Crtr/Event/EventBus.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61741923e2c1d9c43b2d1b457a54ed4c
|
||||
timeCreated: 1617701716
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
39
Assets/Cryville/Crtr/Event/RMVPool.cs
Normal file
39
Assets/Cryville/Crtr/Event/RMVPool.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Cryville.Common.Buffers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Cryville.Crtr.Event {
|
||||
internal class RMVPool {
|
||||
private class Bucket : ObjectPool<RealtimeMotionValue> {
|
||||
MotionRegistry _reg;
|
||||
public Bucket(string name, int capacity) : base(capacity) {
|
||||
_reg = ChartPlayer.motionRegistry[name];
|
||||
}
|
||||
protected override RealtimeMotionValue Construct() {
|
||||
return new RealtimeMotionValue().Init(_reg.InitValue);
|
||||
}
|
||||
}
|
||||
static Dictionary<string, Bucket> _buckets;
|
||||
public static void Prepare() {
|
||||
_buckets = new Dictionary<string, Bucket>(ChartPlayer.motionRegistry.Count);
|
||||
foreach (var reg in ChartPlayer.motionRegistry)
|
||||
_buckets.Add(reg.Key, new Bucket(reg.Key, 4096));
|
||||
}
|
||||
|
||||
Dictionary<RealtimeMotionValue, string> _rented = new Dictionary<RealtimeMotionValue, string>();
|
||||
public RealtimeMotionValue Rent(MotionName name) {
|
||||
var n = name.MainName;
|
||||
var obj = _buckets[n].Rent();
|
||||
_rented.Add(obj, n);
|
||||
return obj;
|
||||
}
|
||||
public void Return(RealtimeMotionValue obj) {
|
||||
_buckets[_rented[obj]].Return(obj);
|
||||
_rented.Remove(obj);
|
||||
}
|
||||
public void ReturnAll() {
|
||||
foreach (var obj in _rented)
|
||||
_buckets[obj.Value].Return(obj.Key);
|
||||
_rented.Clear();
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Cryville/Crtr/Event/RMVPool.cs.meta
Normal file
11
Assets/Cryville/Crtr/Event/RMVPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 765cb7bc1f7fe3e4db42f09a939fc393
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user