using Cryville.Common; using Cryville.Common.Math; using Cryville.Crtr.Components; using Cryville.Crtr.Event; using System; using System.Collections.Generic; using UnityEngine; namespace Cryville.Crtr { public class NoteHandler : ContainerHandler { readonly GroupHandler gh; public readonly Chart.Note Event; public NoteHandler(Chart.Note ev, GroupHandler gh) : base() { Event = ev; this.gh = gh; } public override string TypeName { get { return "note"; } } SectionalGameObject[] sgos; readonly Dictionary judges = new Dictionary(); readonly Dictionary dynJudgeAnchors = new Dictionary(); class JudgeState { static readonly int _var_judge_result = IdentifierManager.SharedInstance.Request("judge_result"); public Anchor StaticAnchor { get; private set; } public DynamicJudgeAnchorPair DynamicAnchors { get; private set; } public bool Judged { get; private set; } public float AbsoluteTime { get; private set; } public float RelativeTime { get; private set; } int _result = 0; PropSrc _resultPropSrc; public JudgeState(NoteHandler handler, int name) { StaticAnchor = handler.RegisterAnchor(handler.judge.judgeMap[name], true); DynamicAnchors = handler.GetDynamicJudgeAnchorPair(name); } public void MarkJudged(float abs, float rel, int result) { Judged = true; AbsoluteTime = abs; RelativeTime = rel; _result = result; _resultPropSrc.Invalidate(); } public void InitPropSrcs() { StaticAnchor.PropSrcs.Add(_var_judge_result, _resultPropSrc = new PropSrc.Identifier(() => _result)); } } class DynamicJudgeAnchorPair { public Anchor Absolute { get; private set; } public Anchor Relative { get; private set; } public DynamicJudgeAnchorPair(Anchor absolute, Anchor relative) { Absolute = absolute; Relative = relative; } } DynamicJudgeAnchorPair GetDynamicJudgeAnchorPair(int name) { DynamicJudgeAnchorPair result; if (!dynJudgeAnchors.TryGetValue(name, out result)) { dynJudgeAnchors.Add(name, result = new DynamicJudgeAnchorPair( RegisterAnchor(judge.jtabsMap[name]), RegisterAnchor(judge.jtrelMap[name]) )); } return result; } public override void PreInit() { base.PreInit(); foreach (var j in Event.judges) { judges.Add(j, new JudgeState(this, j.Id.Key)); } } public override void Init() { base.Init(); sgos = gogroup.GetComponentsInChildren(); foreach (var judge in judges.Values) judge.InitPropSrcs(); } protected override void PreAwake(ContainerState s) { base.PreAwake(s); #if UNITY_5_6_OR_NEWER a_head.Transform.SetPositionAndRotation(Position = GetFramePoint(s.Parent, s.Track), Rotation = GetFrameRotation(s.Parent, s.Track)); #else a_head.Transform.position = Position = GetFramePoint(s.Parent, s.Track); a_head.Transform.rotation = Rotation = GetFrameRotation(s.Parent, s.Track); #endif } protected override void Awake(ContainerState s) { base.Awake(s); if (s.CloneType == 2) { if (!gogroup) return; if (Event.IsLong) { foreach (var i in sgos) { i.Reset(); i.AppendPoint(Position, Rotation); } } else { #if UNITY_5_6_OR_NEWER gogroup.SetPositionAndRotation(Position, Rotation); #else gogroup.position = Position; gogroup.rotation = Rotation; #endif } } } public override void Update(ContainerState s, StampedEvent ev) { base.Update(s, ev); if (s.CloneType <= 2) { Position = GetFramePoint(s.Parent, s.Track); Rotation = GetFrameRotation(s.Parent, s.Track); } if (s.CloneType == 2) { if (!gogroup) return; Chart.Note tev = Event; if (tev.IsLong) { foreach (var i in sgos) i.AppendPoint(Position, Rotation); } } else if (s.CloneType == 16) { if (ev == null) { } else if (ev.Unstamped == null) { } else if (ev.Unstamped is Chart.Judge) { ChartPlayer.etor.ContextEvent = ev.Unstamped; ChartPlayer.etor.ContextState = s; judge.Prepare(ev, this); ChartPlayer.etor.ContextState = null; ChartPlayer.etor.ContextEvent = null; } } } public override void Anchor() { base.Anchor(); foreach (var j in judges.Values) { if (!j.Judged) continue; PushAnchorEvent(j.AbsoluteTime, j.DynamicAnchors.Absolute); PushAnchorEvent(j.RelativeTime + cs.Time, j.DynamicAnchors.Relative); } } public override void EndUpdate(ContainerState s) { if (s.CloneType == 2 && gogroup) { foreach (var i in sgos) i.Seal(); #if UNITY_5_6_OR_NEWER a_tail.Transform.SetPositionAndRotation(GetFramePoint(ts.Parent, ts.Track), Quaternion.Euler(ts.Direction)); #else a_tail.Transform.position = GetFramePoint(ts.Parent, ts.Track); a_tail.Transform.rotation = Quaternion.Euler(ts.Direction); #endif } base.EndUpdate(s); } Vector3 GetFramePoint(ContainerState state, float track) { return GetFrame(state, track, th => ((TrackHandler)th.Handler).GetCurrentWorldPoint()); } Quaternion GetFrameRotation(ContainerState state, float track) { var r = GetFrame(state, track, th => Quaternion.Euler(th.Direction) * Vector3.forward); return Quaternion.LookRotation(r, state.Normal); } readonly List ctrl = new List(2); Vector3 GetFrame(ContainerState state, float track, Func func) { // TODO int id = Mathf.FloorToInt(track); var ts0 = state.GetChild(id, typeof(Chart.Track)); var p1 = func(ts0); if (track == id) return p1; var ts1 = state.GetChild(id + 1, typeof(Chart.Track)); var p2 = func(ts1); bool c0 = ts0.Corner; bool c1 = ts1.Corner; float t = track - id; float deltaz = p2.z - p1.z; float nt = 1 - t; if (c0 && c1) return (1 - t) * p1 + t * p2; else { ctrl.Clear(); if (!c0) { var tp = ts0.GetControlPoint(true, deltaz); if (tp != Vector3.zero) ctrl.Add(tp); } if (!c1) { var tp = ts1.GetControlPoint(false, -deltaz); if (tp != Vector3.zero) ctrl.Add(tp); } if (ctrl.Count == 0) { var frame = gh.GetCurrentFrame(func); return frame.Dot( ColumnVector.WithPolynomialCoefficients( frame.Size, track ), Vector3Operator.Instance ); } else if (ctrl.Count == 1) { return nt * (nt * p1 + t * (ctrl[0] + p1)) + t * t * p2; } else { var t2 = t * t; return nt * (nt * (nt * p1 + t * (ctrl[0] + p1)) + t2 * (ctrl[1] + p1)) + t2 * t * p2; } } } public void ReportJudge(Judge.JudgeEvent ev, float time, Identifier result) { JudgeState state; if (!judges.TryGetValue(ev.BaseEvent, out state)) return; state.MarkJudged(time, (float)(ev.StartTime - time), result.Key); } } }