Files
crtr/Assets/Cryville/Crtr/Judge.cs
2022-09-30 17:32:21 +08:00

732 lines
25 KiB
C#

using Cryville.Common.Pdt;
using Cryville.Common.Unity.Input;
using System.Collections.Generic;
namespace Cryville.Crtr {
#region Obsolete
#if false
[Obsolete]
public class Judge {
/// <summary>
/// The computed positions of the notes.
/// </summary>
readonly Dictionary<StampedEvent.Judge, Vector2> pos
= new Dictionary<StampedEvent.Judge, Vector2>();
struct ActiveJudge : IEquatable<ActiveJudge> {
public StampedEvent.Judge Event;
public NoteHandler NoteHandler;
public bool Equals(ActiveJudge other) {
return Event == other.Event;
}
public override int GetHashCode() {
return Event.GetHashCode();
}
public ActiveJudge(StampedEvent.Judge ev, NoteHandler noteHandler) {
Event = ev; NoteHandler = noteHandler;
}
}
struct JudgeIdentifier : IEquatable<JudgeIdentifier> {
public NoteHandler NoteHandler { get; private set; }
public Chart.Note Note { get { return NoteHandler.Event; } }
public PrimaryJudge TargetJudge { get; private set; }
public int Layer { get { return TargetJudge.layer; } }
public override bool Equals(object obj) {
if (!(obj is JudgeIdentifier)) return false;
return Equals((JudgeIdentifier)obj);
}
public bool Equals(JudgeIdentifier other) {
return NoteHandler.Equals(other.NoteHandler) && Layer == other.Layer;
}
public override int GetHashCode() {
return NoteHandler.GetHashCode() ^ Layer;
}
public JudgeIdentifier(NoteHandler n, PrimaryJudge j) {
NoteHandler = n; TargetJudge = j;
}
}
struct JudgeEventIdentifier {
public JudgeIdentifier JudgeIdentifier { get; private set; }
public StampedEvent.Judge Event { get; private set; }
public JudgeEventIdentifier(JudgeIdentifier jid, StampedEvent.Judge ev) {
JudgeIdentifier = jid;
Event = ev;
}
}
readonly Dictionary<JudgeIdentifier, JudgeState> stateList = new Dictionary<JudgeIdentifier, JudgeState>();
readonly List<JudgeIdentifier> activeList = new List<JudgeIdentifier>();
readonly Dictionary<JudgeIdentifier, List<StampedEvent.Judge>> activeEvents = new Dictionary<JudgeIdentifier, List<StampedEvent.Judge>>();
readonly Dictionary<JudgeIdentifier, PrimaryJudge> immList = new Dictionary<JudgeIdentifier, PrimaryJudge>();
readonly List<StampedEvent.Judge> hitList = new List<StampedEvent.Judge>();
readonly List<JudgeEventIdentifier> missList = new List<JudgeEventIdentifier>();
readonly List<NoteHandler> deactivateList = new List<NoteHandler>();
readonly Dictionary<int, PointerInfo> ptr = new Dictionary<int, PointerInfo>();
readonly List<int> invalidatedPtr = new List<int>();
class JudgeState {
/// <summary>
/// The ID of the pointers currently holding on the note, the first of which is the main pointer.
/// </summary>
public readonly List<int> PointerIds = new List<int>();
/// <summary>
/// The ID of the pointers currently positioned on the note, but not sliding in nor holding down.
/// </summary>
public readonly List<int> NotOwnedPointerIds = new List<int>();
public Vector2 Position;
public Vector2 ImmediatePosition;
}
public readonly Dictionary<string, float> scores = new Dictionary<string, float>();
readonly CompiledRuleset ruleset;
public Judge(CompiledRuleset r) {
ruleset = r;
foreach (var s in r.scores)
scores.Add(s.Key, s.Value.init);
}
public void RecordPos(StampedEvent.Judge ev, Vector2 pt) { pos[ev] = pt; }
internal void Issue(StampedEvent.Judge ev, NoteHandler nh) {
// Logger.Log("main", 0, "Judge", "Issue: {0} {1} {2}", ev.Time, ev.Container.GetHashCode(), ruleset.primary_judges.First(i => i.Value == ev.TargetJudge).Key);
// var u = new ActiveJudge(ev, nh);
/*if (ev.TargetJudge.PassCh.ContainsKey("br"))
Logger.Log("main", 0, "Judge", "{0}", ev.StartEvent == null);*/
if (ev.StartEvent != null) {
var jid = new JudgeIdentifier(nh, ev.StartEvent.TargetJudge);
int i = activeList.IndexOf(jid);
if (i >= 0) missList.Add(new JudgeEventIdentifier(jid, ev.StartEvent));
}
else {
var jid = new JudgeIdentifier(nh, ev.TargetJudge);
if (!activeList.Contains(jid)) {
var i = activeList.FindLastIndex(j => j.TargetJudge.priority <= ev.TargetJudge.priority);
activeList.Insert(i + 1, jid);
}
if (!activeEvents.ContainsKey(jid)) activeEvents.Add(jid, new List<StampedEvent.Judge> { ev });
else activeEvents[jid].Add(ev);
if (!stateList.ContainsKey(jid)) {
stateList.Add(jid, CreateJudgeState(ev.TargetJudge, pos[ev]));
}
stateList[jid].Position = pos[ev];
}
}
internal void IssueImmediate(NoteHandler nh, string pjn, Vector2 pt) {
var key = new JudgeIdentifier(nh, ruleset.primary_judges[pjn]);
if (!immList.ContainsKey(key)) immList.Add(key, ruleset.primary_judges[pjn]);
if (!stateList.ContainsKey(key)) {
stateList.Add(key, CreateJudgeState(ruleset.primary_judges[pjn], pt));
}
stateList[key].ImmediatePosition = pt;
}
JudgeState CreateJudgeState(PrimaryJudge judge, Vector2 pt) {
var state = new JudgeState();
var etor = new Evaluator();
foreach (var p in ptr) {
var info = p.Value;
var wp = ScreenToWorldPoint(info.Position);
etor.Context = new EvaluatorContext {
Extra = new Dictionary<string, object> {
{ "npos", pt },
{ "-hitpos", wp }
}
};
if (MatchArea(judge.PassCh.Values.First().area, etor))
state.NotOwnedPointerIds.Add(info.Id);
}
return state;
}
Vector2 ScreenToWorldPoint(Vector2 pp) {
Vector3 sp = pp;
sp.y = Screen.height - sp.y;
sp.z = -Camera.main.transform.position.z;
return Camera.main.ScreenToWorldPoint(sp);
}
public void NewFrame() {
ptr.Clear();
}
public void Feed(PointerInfo info) {
var etor = new Evaluator();
var wp = ScreenToWorldPoint(info.Position);
foreach (var u in activeList) {
foreach (var j in activeEvents[u]) {
var t = j.NoteTime;
var deltat = info.Time - t;
var pj = j.TargetJudge;
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "npos", pos[j] },
{ "-hitpos", wp }
}
};
foreach (var sj in pj.PassCh) {
var flag = false;
if (!MatchSecondaryJudge(u.NoteHandler, info.Id, stateList[u], sj.Value, j.IsEndJudge, info, deltat, wp, etor))
continue;
foreach (var tj in sj.Value.PassCh) {
if (!MatchTertiaryJudge(tj.Value, deltat, wp, etor))
continue;
// TODO Fire hit input
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Hit F: {0} {1}", sj.Key, tj.Key);
hitList.Add(j);
flag = true; break;
}
if (flag) break;
}
}
FlushHitList(u);
}
FlushDeactivateList();
foreach (var u in immList) {
var pj = u.Value;
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "-hitpos", wp }
}
};
foreach (var sj in pj.PassCh) {
if (!MatchSecondaryJudge(u.Key.NoteHandler, info.Id, stateList[u.Key], sj.Value, false, info, 0, wp, etor, true))
continue;
if (MatchImmJudgeSubProcess(u.Key.NoteHandler, info.Id, sj.Key, sj.Value, sj.Value.type.ToString(), false, 0, wp, etor))
break;
}
}
}
public void Update(PointerInfo info) {
var etor = new Evaluator();
var wp = ScreenToWorldPoint(info.Position);
foreach (var u in activeList) {
foreach (var j in activeEvents[u]) {
var t = j.NoteTime;
var deltat = info.Time - t;
var pj = j.TargetJudge;
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "npos", pos[j] },
{ "-hitpos", wp }
}
};
foreach (var sj in pj.PassCh) {
var flag = false;
if (!MatchSecondaryActiveJudge(u.NoteHandler, info.Id, stateList[u], sj.Value, j.IsEndJudge, info, deltat, wp, etor))
continue;
foreach (var tj in sj.Value.PassCh) {
if (!MatchTertiaryJudge(tj.Value, deltat, wp, etor))
continue;
// TODO Fire hit input
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Hit U: {0} {1}", sj.Key, tj.Key);
hitList.Add(j);
flag = true; break;
}
if (flag) break;
}
}
FlushHitList(u);
}
FlushDeactivateList();
if (!invalidatedPtr.Contains(info.Id)) ptr[info.Id] = info;
}
public void Trash(double time) {
var etor = new Evaluator();
foreach (var u in activeList) {
foreach (var j in activeEvents[u]) {
if (MatchImmJudge(u.NoteHandler, j.TargetJudge, j.IsEndJudge, time - j.NoteTime, stateList[u], etor))
hitList.Add(j);
}
// Logger.Log("main", 0, "Judge", "Active Events: {0}", activeEvents[u].Count);
FlushHitList(u);
}
FlushDeactivateList();
// Logger.Log("main", 0, "Judge", "Active States: {0}", activeList.Count);
foreach (var u in missList) {
// TODO this check shouldn't be done here, instead, invalidate/compensate those already in the active events
if (!activeEvents.ContainsKey(u.JudgeIdentifier)) continue;
var evs = activeEvents[u.JudgeIdentifier];
var ev = u.Event;
if (!evs.Contains(ev)) continue;
var pj = ev.TargetJudge;
var flag = false;
foreach (var sj in pj.PassCh) {
if (!MatchSecondaryMissJudge(u.JudgeIdentifier.NoteHandler, sj.Value, etor))
continue;
foreach (var tj in sj.Value.PassCh) {
/*if (!MatchTertiaryJudge(j, tj.Value, etor))
continue;*/
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Miss: {0}", tj.Key);
flag = true; break;
}
if (flag) break;
}
if (!flag)
Logger.Log("main", 3, "Judge", "Unjudged miss");
evs.Remove(ev);
if (u.Event.IsEndJudge) deactivateList.Add(u.JudgeIdentifier.NoteHandler);
}
FlushDeactivateList();
missList.Clear();
foreach (var j in immList) {
MatchImmJudge(j.Key.NoteHandler, j.Value, false, 0, stateList[j.Key], etor);
}
/*var rmimm = new List<JudgeIdentifier>();
foreach (var i in immList) {
if (i.Value.Active) i.Value.Active = false;
else rmimm.Add(i.Key);
}
foreach (var i in rmimm) immList.Remove(i);*/
// Logger.Log("main", 0, "Judge", "Active List: {0}", activeList.Count);
immList.Clear();
}
void FlushHitList(JudgeIdentifier jid) {
if (activeEvents.ContainsKey(jid))
foreach (var j in hitList) {
activeEvents[jid].Remove(j);
// TODO items in stateList need to be destroyed
}
hitList.Clear();
}
void FlushDeactivateList() {
for (int i = activeList.Count - 1; i >= 0; i--) {
if (deactivateList.Contains(activeList[i].NoteHandler)) {
activeEvents.Remove(activeList[i]);
activeList.RemoveAt(i);
}
}
deactivateList.Clear();
}
bool MatchImmJudge(NoteHandler nh, PrimaryJudge pj, bool endjudge, double deltat, JudgeState v, Evaluator etor) {
bool flag = false;
var ptrids = new Dictionary<int, int>();
foreach (var sj in pj.PassCh) {
var wp = ScreenToWorldPoint(v.ImmediatePosition);
ptrids.Clear();
foreach (var p in ptr) {
int id = p.Key;
Vector3 sp2 = p.Value.Position;
sp2.y = Screen.height - sp2.y;
sp2.z = -Camera.main.transform.position.z;
var wp2 = (Vector2)Camera.main.ScreenToWorldPoint(sp2);
etor.Context = new EvaluatorContext() {
Extra = new Dictionary<string, object>() {
{ "npos", v.Position },
{ "-hitpos", wp2 }
}
};
if (MatchArea(sj.Value.area, etor)) {
if (v.NotOwnedPointerIds.Contains(id)) continue;
bool flag2 = !v.PointerIds.Contains(id);
if (flag2) ptrids.Add(id, 1);
if (flag) continue;
if (sj.Value.type.HasFlag(JudgeType.enterp)) {
if (v.PointerIds.Count == 0) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "enterp", endjudge, deltat, wp, etor);
}
}
else if (sj.Value.type.HasFlag(JudgeType.enters)) {
if (v.PointerIds.Count > 0) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "enters", endjudge, deltat, wp, etor);
}
}
if (flag && sj.Value.@override && flag2) ptrids[id] = 2;
// else if ((int)sj.Value.type >= 4096) continue;
/*if (!v.PointerIds.Contains(id)) {
// Logger.Log("main", 0, "Judge", "push {0}", id);
if (sj.Value.@override) v.PointerIds.Insert(0, id);
else v.PointerIds.Add(id);
}*/
}
else {
if (v.PointerIds.Contains(id)) ptrids.Add(id, 0);
if (v.NotOwnedPointerIds.Contains(id)) ptrids.Add(id, -1);
if (flag) continue;
if (sj.Value.type.HasFlag(JudgeType.leaveb)) {
// Logger.Log("main", 0, "Judge", "POS {0}", v.Position);
if (v.PointerIds.Count == 1 && v.PointerIds[0] == id) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "leaveb", endjudge, deltat, wp, etor);
}
}
else if (sj.Value.type.HasFlag(JudgeType.leavec)) {
if (v.PointerIds.Count > 1 && v.PointerIds[0] == id) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "leavec", endjudge, deltat, wp, etor);
}
}
else if (sj.Value.type.HasFlag(JudgeType.leaves)) {
if (v.PointerIds.Count > 1 && v.PointerIds.IndexOf(id) > 0) {
flag = MatchImmJudgeSubProcess(nh, p.Key, sj.Key, sj.Value, "leaves", endjudge, deltat, wp, etor);
}
}
// else if ((int)sj.Value.type >= 4096) continue;
/*if (v.PointerIds.Contains(id)) {
// Logger.Log("main", 0, "Judge", "pop {0}", id);
v.PointerIds.Remove(id);
}*/
}
}
if (flag) {
foreach (var i in ptrids) {
switch (i.Value) {
case -1: v.NotOwnedPointerIds.Remove(i.Key); break;
case 0: v.PointerIds.Remove(i.Key); break;
case 1: v.PointerIds.Add(i.Key); break;
case 2: v.PointerIds.Insert(0, i.Key); break;
}
}
// Logger.Log("main", 0, "Judge", "{0}", v.PointerIds.Count);
return true;
}
}
foreach (var i in ptrids) {
switch (i.Value) {
case -1: v.NotOwnedPointerIds.Remove(i.Key); break;
case 0: v.PointerIds.Remove(i.Key); break;
case 1: v.PointerIds.Add(i.Key); break;
case 2: v.PointerIds.Insert(0, i.Key); break;
}
}
return false;
}
bool MatchImmJudgeSubProcess(NoteHandler nh, int ptrid, string sj_name, SecondaryJudge sj, string judge_type, bool endjudge, double deltat, Vector2 wp, IEvaluator etor) {
TryInvalidate(nh, sj, ptrid);
if (endjudge) Compensate(nh);
foreach (var tj in sj.PassCh) {
if (MatchTertiaryJudge(tj.Value, deltat, wp, etor)) {
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Hit I {2}: {0} {1}", sj_name, tj.Key, judge_type);
return true;
}
}
return false;
}
void TryInvalidate(NoteHandler nh, SecondaryJudge sj, int ptrid) {
if (sj.invalidate.HasFlag(Invalidation.finger) && ptrid != -1) {
invalidatedPtr.Add(ptrid);
ptr.Remove(ptrid);
}
if (sj.invalidate.HasFlag(Invalidation.note)) {
List<StampedEvent.Judge> invalidatedList = nh.Invalidate();
// TODO also handle events in `activeEvents`
foreach (var j in invalidatedList) {
if (j.StartEvent != null) continue;
Invalidate(j);
}
deactivateList.Add(nh);
}
}
void Invalidate(StampedEvent.Judge j) {
bool flag = false;
foreach (var sj in j.TargetJudge.PassCh) {
if (!sj.Value.type.HasFlag(JudgeType.invalidate)) continue;
foreach (var tj in sj.Value.PassCh) {
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Invalidate: {0}", tj.Key);
flag = true; break;
}
if (flag) break;
}
if (!flag) Logger.Log("main", 3, "Judge", "Unjudged invalidation");
}
void Compensate(NoteHandler nh) {
List<StampedEvent.Judge> compensateList = nh.Invalidate();
// Logger.Log("main", 0, "Judge", "comp {0}", compensateList.Count);
// TODO also handle events in `activeEvents`
foreach (var j in compensateList) {
if (j.StartEvent != null) continue;
bool flag = false;
foreach (var sj in j.TargetJudge.PassCh) {
if (!sj.Value.type.HasFlag(JudgeType.compensate)) continue;
foreach (var tj in sj.Value.PassCh) {
foreach (var s in tj.Value.scores)
UpdateScore(s.Key, s.Value);
Logger.Log("main", 0, "Judge", "Compensate: {0}", tj.Key);
flag = true; break;
}
if (flag) break;
}
if (!flag) Logger.Log("main", 3, "Judge", "Unjudged compensation");
}
deactivateList.Add(nh);
}
/// <summary>
/// Matches an attack or release judge.
/// </summary>
bool MatchSecondaryJudge(NoteHandler nh, int ptrid, JudgeState state, SecondaryJudge sj, bool endjudge, PointerInfo p, double deltat, Vector2 wp, IEvaluator etor, bool immsec = false) {
bool flag = false;
int pid = p.Id;
var phase = p.Phase;
if (sj.type == JudgeType.none) return false;
if (!immsec && sj.area != null) if (!MatchArea(sj.area, etor)) return false;
if (phase == PointerPhase.Begin) {
if (sj.type.HasFlag(JudgeType.attackp)) {
if (state.PointerIds.Count == 0) flag = true;
}
if (sj.type.HasFlag(JudgeType.attacks)) {
if (state.PointerIds.Count > 0) flag = true;
}
/*if (!state.PointerIds.Contains(pid)) {
if (sj.@override) ptrop = 2;
else ptrop = 1;
}*/
}
if (phase.HasFlag(PointerPhase.End)) {
if (sj.type.HasFlag(JudgeType.releaseb)) {
if (state.PointerIds.Count == 1 && state.PointerIds[0] == pid) flag = true;
}
if (sj.type.HasFlag(JudgeType.releasec)) {
if (state.PointerIds.Count > 1 && state.PointerIds[0] == pid) flag = true;
}
if (sj.type.HasFlag(JudgeType.releases)) {
if (state.PointerIds.IndexOf(pid) > 0) flag = true;
}
//if (state.PointerIds.IndexOf(pid) >= 0) ptrop = 0;
}
if (!flag) return false;
if (sj.time != null) {
var tr = sj.time.Eval<List<float>>(etor);
if (deltat < tr[0] || deltat > tr[1]) return false;
}
if (endjudge) Compensate(nh);
TryInvalidate(nh, sj, ptrid);
return true;
}
/// <summary>
/// Matches a contact judge.
/// </summary>
bool MatchSecondaryActiveJudge(NoteHandler nh, int ptrid, JudgeState state, SecondaryJudge sj, bool endjudge, PointerInfo p, double deltat, Vector2 wp, IEvaluator etor) {
bool flag = false;
int pid = p.Id;
// Logger.Log("main", 0, "Judge", "Pointers: {0}", state.PointerIds.Count);
if (sj.type == JudgeType.none) return false;
if (sj.type.HasFlag(JudgeType.contactp)) {
if (state.PointerIds.Count > 0 && pid == state.PointerIds[0]) flag = true;
}
if (sj.type.HasFlag(JudgeType.contacts)) {
if (state.PointerIds.Count > 0 && pid != state.PointerIds[0]) flag = true;
// if (sj.@override) stateList[j].PointerId = pid;
}
if (!flag) return false;
if (sj.time != null) {
var tr = sj.time.Eval<List<float>>(etor);
if (deltat < tr[0] || deltat > tr[1]) return false;
}
if (!MatchArea(sj.area, etor)) return false;
TryInvalidate(nh, sj, ptrid);
if (endjudge) Compensate(nh);
return true;
// TODO Invalidate & Call
}
bool MatchSecondaryMissJudge(NoteHandler nh, SecondaryJudge sj, Evaluator etor) {
if (sj.type.HasFlag(JudgeType.miss)) {
TryInvalidate(nh, sj, -1);
return true;
}
return false;
}
bool MatchTertiaryJudge(TertiaryJudge tj, double deltat, Vector3 wp, IEvaluator etor) {
if (tj.time != null) {
var tr = tj.time.Eval<List<float>>(etor);
if (deltat < tr[0] || deltat > tr[1]) return false;
}
if (!MatchArea(tj.area, etor)) return false;
return true;
}
bool MatchArea(Expression exp, IEvaluator etor) {
if (exp != null) {
var a = exp.Eval<float>(etor);
if (a > 0) return false;
}
return true;
}
void UpdateScore(string key, Expression value) {
var etor = new Evaluator();
var extra = new Dictionary<string, object>(scores.Count);
foreach (var s in scores) extra.Add(s.Key, s.Value);
etor.Context = new EvaluatorContext() { Extra = extra };
var ak = key.Split(' ');
string name = ak[ak.Length - 1];
bool setMode = false;
float result = scores[name];
var prop = ruleset.scores[name];
if (ak.Length > 1)
for (int i = 0; i < ak.Length - 1; i++)
if (ak[i] == "@set") setMode = true;
if (setMode)
result = value.Eval<float>(etor);
else
result += value.Eval<float>(etor);
if (prop.range != null) {
var range = prop.range.Eval<List<float>>(etor);
if (result < range[0]) result = range[0];
else if (result > range[1]) result = range[1];
}
if (prop.min != null && result < scores[prop.min])
scores[prop.min] = result;
if (prop.max != null && result > scores[prop.max])
scores[prop.max] = result;
scores[name] = result;
foreach (var s in scores) extra[s.Key] = s.Value;
etor.Context = new EvaluatorContext() { Extra = extra };
foreach (var s in ruleset.scores.Keys) {
if (ruleset.scores[s].value != null) {
scores[s] = ruleset.scores[s].value.Eval<float>(etor);
}
}
ScoreCache.Clear();
}
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>();
public Dictionary<string, string> GetScoreStrings() {
if (ScoreCache.Count == 0) {
foreach (var s in scores) {
ScoreCache.Add(s.Key, s.Value.ToString(ruleset.scores[s.Key].format));
}
}
return ScoreCache;
}
public string FormatScores() {
using (gstring.Block()) {
bool flag = false;
gstring result = new gstring(0);
foreach (var s in GetScoreStrings()) {
result += gstring.Format(flag ? "\n{0}: {1}" : "{0}: {1}", s.Key, (string)s.Value);
flag = true;
}
return result.Intern();
}
}
}
[Obsolete]
public class PrimaryJudge {
public List<string> pass;
public Dictionary<string, SecondaryJudge> PassCh
= new Dictionary<string, SecondaryJudge>();
public Expression time;
/// <summary>
/// The layer of the primary judge. Judges on different layers do not interfere with each other.
/// </summary>
public int layer = 0;
/// <summary>
/// The priority of the primary judge. Judges with higher priority are handled first on the same layer.
/// </summary>
public int priority = 0;
}
[Obsolete]
public class SecondaryJudge {
public JudgeType type;
public List<string> call;
public Dictionary<string, SecondaryJudge> CallCh
= new Dictionary<string, SecondaryJudge>();
public bool @return;
public List<string> pass;
public Dictionary<string, TertiaryJudge> PassCh
= new Dictionary<string, TertiaryJudge>();
public Expression time;
public Expression area;
public Invalidation invalidate;
public bool @override;
}
[Flags][Obsolete]
public enum JudgeType {
none = 0,
attackp = 1, attacks = 2, attack = 3,
releaseb = 4, releasec = 8, releasep = 12, releases = 16, release = 28,
enterp = 32, enters = 64, enter = 96,
leaveb = 128, leavec = 256, leavep = 384, leaves = 512, leave = 896,
setp = 33, sets = 66, set = 99,
unsetb = 132, unsetc = 264, unsetp = 396, unsets = 528, unset = 924,
contactp = 1024, contacts = 2048, contact = 3072,
miss = 4096, compensate = 8192, invalidate = 16384
}
[Flags][Obsolete]
public enum Invalidation {
none = 0, finger = 1, note = 2
}
[Obsolete]
public class TertiaryJudge {
public Expression time;
public Expression area;
public Dictionary<string, Expression> scores
= new Dictionary<string, Expression>();
}
[Obsolete]
public class Score {
public Expression range;
public Expression value;
public float init = 0;
public string min;
public string max;
public string format = "";
}
#endif
#endregion
public class Judge {
readonly PdtRuleset rs;
public Judge() {
rs = ChartPlayer.pruleset;
foreach (var s in rs.scores)
scores.Add(s.Key, s.Value.init);
}
public void StartFrame() {
}
public void Feed(InputEvent ev) {
}
public void EndFrame() {
}
public readonly Dictionary<string, float> scores = new Dictionary<string, float>();
readonly Dictionary<string, string> ScoreCache = new Dictionary<string, string>();
public Dictionary<string, string> GetFormattedScoreStrings() {
if (ScoreCache.Count == 0) {
foreach (var s in scores)
ScoreCache.Add(s.Key, s.Value.ToString(rs.scores[s.Key].format));
}
return ScoreCache;
}
public string GetFullFormattedScoreString() {
bool flag = false;
string result = "";
foreach (var s in GetFormattedScoreStrings()) {
result += string.Format(flag ? "\n{0}: {1}" : "{0}: {1}", s.Key, s.Value);
flag = true;
}
return result;
}
}
public class InputDefinition {
public int dim;
public bool notnull;
public Dictionary<string, PdtExpression> pass;
}
public class JudgeDefinition {
public PdtExpression clip;
public PdtExpression hit;
public string[] pass;
public string miss;
public Dictionary<string, PdtExpression> scores;
}
public class ScoreOperation {
public string name;
public PdtOperator op;
}
public class ScoreDefinition {
public PdtExpression value;
public float init = 0;
public string format = "";
}
}