Add stub for "call" judge action.

This commit is contained in:
2023-06-02 18:20:20 +08:00
parent d5ba09cbea
commit 832facdf5b
2 changed files with 61 additions and 13 deletions

View File

@@ -16,7 +16,7 @@ namespace Cryville.Crtr {
public float? Time { get; set; }
public Vector4 Vector { get; set; }
}
internal struct JudgeEvent {
internal class JudgeEvent {
public double StartTime { get; set; }
public double EndTime { get; set; }
public double StartClip { get; set; }
@@ -25,8 +25,16 @@ namespace Cryville.Crtr {
public JudgeDefinition Definition { get; set; }
public NoteHandler Handler { get; set; }
public JudgeResult JudgeResult { get; set; }
public JudgeCallContext CallContext { get; set; }
}
internal struct JudgeCallContext {
public bool CalledOnMiss { get; set; }
public float CallTime { get; set; }
public JudgeEvent ReturnEvent { get; set; }
public int ReturnIndex { get; set; }
}
internal interface IJudge {
void Call(JudgeEvent ev, float time, Identifier id, bool onMiss, int index);
bool Pass(JudgeEvent ev, float time, Identifier[] ids, int depth);
void UpdateScore(ScoreOperation op, PdtExpression exp);
}
@@ -85,7 +93,7 @@ namespace Cryville.Crtr {
var tev = (Chart.Judge)sev.Unstamped;
InsertEvent(tev, new Clip((float)sev.Time, (float)(sev.Time + sev.Duration)), tev.Id, handler);
}
void InsertEvent(Chart.Judge ev, Clip clip, Identifier id, NoteHandler handler) {
void InsertEvent(Chart.Judge ev, Clip clip, Identifier id, NoteHandler handler, JudgeCallContext call = default(JudgeCallContext)) {
if (id.Key == _var_pause) throw new InvalidOperationException("Cannot assign the special judge \"pause\" to notes");
var def = _rs.judges[id];
_etor.Evaluate(_identop, def.input);
@@ -99,6 +107,7 @@ namespace Cryville.Crtr {
BaseEvent = ev,
Definition = def,
Handler = handler,
CallContext = call,
};
var index = list.BinarySearch(jev, _stcmp);
if (index < 0) index = ~index;
@@ -236,7 +245,7 @@ namespace Cryville.Crtr {
_numbuf2 = (float)hitEvent.EndTime; _numsrc2.Invalidate(); _etor.ContextCascadeUpdate(_var_tn, _numsrc2);
var def = hitEvent.Definition;
if (def == _judgePause) _sys.TogglePause();
if (def.on_hit != null) Execute(hitEvent, (ft + tt) / 2, def.on_hit);
if (def.on_hit != null) Execute(hitEvent, (ft + tt) / 2, def.on_hit, false);
if (def.persist != null) _etor.Evaluate(_flagop, def.persist);
else _flag = false;
if (!_flag) {
@@ -259,7 +268,7 @@ namespace Cryville.Crtr {
JudgeEvent ev = actlist[i];
if (tt > ev.EndClip) {
actlist.RemoveAt(i);
if (ev.Definition.on_miss != null) Execute(ev, tt, ev.Definition.on_miss);
Execute(ev, tt, ev.Definition.on_miss, true);
}
}
}
@@ -275,14 +284,36 @@ namespace Cryville.Crtr {
actlist.Insert(index, ev);
}
}
void Execute(JudgeEvent ev, float time, PairList<JudgeAction, PdtExpression> actions, int depth = 0) {
void Execute(JudgeEvent ev, float time, PairList<JudgeAction, PdtExpression> actions, bool onMiss, int depth = 0, int index = 0) {
if (ev.JudgeResult.Time != null) {
_jnumbuf = ev.JudgeResult.Time.Value; _jnumsrc.Invalidate(); _etor.ContextCascadeUpdate(_var_jt, _jnumsrc);
_jvecbuf = ev.JudgeResult.Vector; _jvecsrc.Invalidate(); _etor.ContextCascadeUpdate(_var_jv, _jvecsrc);
}
foreach (var a in actions) {
if (a.Key.Execute(this, ev, time, a.Value, depth)) break;
if (actions != null) {
// Ensure that all actions that modifies judge result sources break the execution
for (int i = index; i < actions.Count; i++) {
var a = actions[i];
if (a.Key.Execute(this, ev, time, a.Value, onMiss, depth, i).BreakExecution) break;
}
}
else {
var call = ev.CallContext;
if (call.ReturnEvent != null) {
// TODO
if (onMiss)
Execute(call.ReturnEvent, time, call.ReturnEvent.Definition.on_miss, true, depth + 1, 0);
else
Execute(call.ReturnEvent, time, call.ReturnEvent.Definition.on_hit, false, depth + 1, call.ReturnIndex);
}
}
}
void IJudge.Call(JudgeEvent ev, float time, Identifier id, bool onMiss, int index) {
InsertEvent(ev.BaseEvent, new Clip((float)ev.StartTime, (float)ev.EndTime), id, ev.Handler, new JudgeCallContext {
CalledOnMiss = onMiss,
CallTime = time,
ReturnEvent = ev,
ReturnIndex = index + 1,
}); // TODO optimize GC
}
bool IJudge.Pass(JudgeEvent ev, float time, Identifier[] ids, int depth) {
if (depth >= 16) throw new JudgePropagationException();
@@ -296,7 +327,7 @@ namespace Cryville.Crtr {
}
else hitFlag = true;
if (hitFlag) {
Execute(ev, time, def.on_hit, depth + 1);
Execute(ev, time, def.on_hit, false, depth + 1);
ev.Handler.ReportJudge(ev, time, i);
return true;
}

View File

@@ -5,11 +5,18 @@ using System.Collections.Generic;
using System.Linq;
namespace Cryville.Crtr {
internal struct JudgeActionResult {
public bool BreakExecution;
public bool PreventRecycle;
}
public abstract class JudgeAction {
public static JudgeAction Construct(HashSet<string> a, string k) {
if (a.Remove("pass")) {
return new Pass(a, from i in k.Split(',') select new Identifier(i.Trim()));
}
else if (a.Remove("call")) {
return new Call(a, new Identifier(k));
}
else if (a.Remove("score")) {
return new Score(a, k);
}
@@ -20,14 +27,24 @@ namespace Cryville.Crtr {
annotations = a.ToHashSet();
}
public virtual void Optimize(PdtEvaluatorBase etor, PdtExpression value) { etor.Optimize(value); }
internal abstract bool Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, int depth);
internal abstract JudgeActionResult Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, bool onMiss, int depth, int index);
public class Call : JudgeAction {
readonly Identifier _target;
public Call(IEnumerable<string> a, Identifier k) : base(a) {
_target = k;
}
internal override JudgeActionResult Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, bool onMiss, int depth, int index) {
judge.Call(ev, time, _target, onMiss, index);
return new JudgeActionResult { BreakExecution = true, PreventRecycle = true };
}
}
public class Pass : JudgeAction {
readonly Identifier[] _targets;
public Pass(IEnumerable<string> a, IEnumerable<Identifier> k) : base(a) {
_targets = k.ToArray();
}
internal override bool Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, int depth) {
return judge.Pass(ev, time, _targets, depth);
internal override JudgeActionResult Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, bool onMiss, int depth, int index) {
return new JudgeActionResult { BreakExecution = judge.Pass(ev, time, _targets, depth) };
}
}
public class Score : JudgeAction {
@@ -42,9 +59,9 @@ namespace Cryville.Crtr {
base.Optimize(etor, value);
if (_op.op != default(Identifier)) PdtExpression.PatchCompound(_op.name.Key, _op.op.Key, value);
}
internal override bool Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, int depth) {
internal override JudgeActionResult Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, bool onMiss, int depth, int index) {
judge.UpdateScore(_op, exp);
return false;
return new JudgeActionResult();
}
}
}