Files
crtr/Assets/Cryville/Crtr/Event/ContainerState.cs
2022-11-01 11:28:48 +08:00

428 lines
12 KiB
C#

//#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>();
readonly HashSet<EventContainer> WorkingChildren
= new HashSet<EventContainer>();
readonly 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) {
return Children[ev];
}
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 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) {
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));
}
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) {
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) {
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());
}
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) {
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_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) return;
if (ev != null) {
if (ev.Unstamped is Chart.Motion) {
var tev = (Chart.Motion)ev.Unstamped;
var mv = RMVPool.Rent(tev.Name);
GetMotionValue(tev.Name).CopyTo(mv);
PlayingMotions.Add(ev, mv);
Callback(ev, callback);
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) {
Callback(ev, callback);
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();
}
}
}
Callback(ev.Unstamped == null || ev.Unstamped.Priority >= 0 ? ev : null, callback);
}
else 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);
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();
}
}
}
}