Add judge action fields on_hit and on_miss.

This commit is contained in:
2023-05-20 16:23:59 +08:00
parent d1b9b9607b
commit 25b4f3ccb7
5 changed files with 151 additions and 42 deletions

View File

@@ -20,6 +20,11 @@ namespace Cryville.Crtr {
public JudgeDefinition Definition { get; set; }
public NoteHandler Handler { get; set; }
}
public interface IJudge {
bool Pass(JudgeEvent ev, float time, Identifier[] ids, int depth);
void UpdateScore(ScoreOperation op, PdtExpression exp);
}
public class Judge : IJudge {
#region Data
readonly ChartPlayer _sys;
internal readonly PdtEvaluator _etor;
@@ -193,8 +198,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.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(hitEvent, (ft + tt) / 2, def.pass);
if (def.on_hit != null) Execute(hitEvent, (ft + tt) / 2, def.on_hit);
if (def.persist != null) _etor.Evaluate(_flagop, def.persist);
else _flag = false;
if (!_flag) {
@@ -209,21 +213,6 @@ namespace Cryville.Crtr {
}
}
}
bool Pass(JudgeEvent ev, float time, Identifier[] ids, int depth = 0) {
if (depth >= 16) throw new JudgePropagationException();
foreach (var i in ids) {
var def = _rs.judges.Judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (def.scores != null) UpdateScore(def.scores);
if (def.pass != null) Pass(ev, time, def.pass, depth + 1);
ev.Handler.ReportJudge(ev, time, i);
return true;
}
}
return false;
}
public void Cleanup(Identifier target, float tt) {
lock (_etor) {
Forward(target, tt);
@@ -232,7 +221,7 @@ namespace Cryville.Crtr {
JudgeEvent ev = actlist[i];
if (tt > ev.EndClip) {
actlist.RemoveAt(i);
if (ev.Definition.miss != null) Pass(ev, tt, ev.Definition.miss);
if (ev.Definition.on_miss != null) Execute(ev, tt, ev.Definition.on_miss);
}
}
}
@@ -248,18 +237,34 @@ namespace Cryville.Crtr {
actlist.Insert(index, ev);
}
}
void UpdateScore(PairList<ScoreOperation, PdtExpression> scoreops) {
foreach (var scoreop in scoreops) {
var key = scoreop.Key;
_etor.ContextSelfValue = scoreSrcs[key.name.Key];
_etor.Evaluate(scoreOps[key.name.Key], scoreop.Value);
InvalidateScore(key.name.Key);
foreach (var s in _rs.scores) {
if (s.Value.value != null) {
_etor.ContextSelfValue = scoreSrcs[s.Key.Key];
_etor.Evaluate(scoreOps[s.Key.Key], s.Value.value);
InvalidateScore(s.Key.Key);
}
void Execute(JudgeEvent ev, float time, PairList<JudgeAction, PdtExpression> actions, int depth = 0) {
foreach (var a in actions) {
if (a.Key.Execute(this, ev, time, a.Value, depth)) break;
}
}
bool IJudge.Pass(JudgeEvent ev, float time, Identifier[] ids, int depth) {
if (depth >= 16) throw new JudgePropagationException();
foreach (var i in ids) {
var def = _rs.judges.Judges[i];
if (def.hit != null) _etor.Evaluate(_flagop, def.hit);
else _flag = true;
if (_flag) {
if (def.on_hit != null) Execute(ev, time, def.on_hit, depth + 1);
ev.Handler.ReportJudge(ev, time, i);
return true;
}
}
return false;
}
void IJudge.UpdateScore(ScoreOperation op, PdtExpression exp) {
_etor.ContextSelfValue = scoreSrcs[op.name.Key];
_etor.Evaluate(scoreOps[op.name.Key], exp);
InvalidateScore(op.name.Key);
foreach (var s in _rs.scores) {
if (s.Value.value != null) {
_etor.ContextSelfValue = scoreSrcs[s.Key.Key];
_etor.Evaluate(scoreOps[s.Key.Key], s.Value.value);
InvalidateScore(s.Key.Key);
}
}
}

View File

@@ -0,0 +1,52 @@
using Cryville.Common;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Cryville.Crtr {
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("score")) {
return new Score(a, k);
}
throw new FormatException("Invalid judge action format.");
}
public readonly HashSet<string> annotations;
public JudgeAction(IEnumerable<string> a) {
annotations = a.ToHashSet();
}
public virtual void Optimize(PdtEvaluatorBase etor, PdtExpression value) { etor.Optimize(value); }
public abstract bool Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, int depth);
public class Pass : JudgeAction {
readonly Identifier[] _targets;
public Pass(IEnumerable<string> a, IEnumerable<Identifier> k) : base(a) {
_targets = k.ToArray();
}
public override bool Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, int depth) {
return judge.Pass(ev, time, _targets, depth);
}
}
public class Score : JudgeAction {
readonly ScoreOperation _op;
public Score(IEnumerable<string> a, string k) : base(a) {
_op = new ScoreOperation(k);
}
public Score(ScoreOperation op) : base(Enumerable.Empty<string>()) {
_op = op;
}
public override void Optimize(PdtEvaluatorBase etor, PdtExpression value) {
base.Optimize(etor, value);
if (_op.op != default(Identifier)) PdtExpression.PatchCompound(_op.name.Key, _op.op.Key, value);
}
public override bool Execute(IJudge judge, JudgeEvent ev, float time, PdtExpression exp, int depth) {
judge.UpdateScore(_op, exp);
return false;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7e5a4fc83d8c4a4db15856783b8a145
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -6,7 +6,9 @@ using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Cryville.Crtr {
public class Ruleset : MetaInfo {
@@ -44,13 +46,8 @@ namespace Cryville.Crtr {
foreach (var j in judges.Judges) {
var judge = j.Value;
if (judge.hit != null) etor.Optimize(judge.hit);
if (judge.scores != null) {
foreach (var s in judge.scores) {
if (s.Key.op != default(Identifier))
PdtExpression.PatchCompound(s.Key.name.Key, s.Key.op.Key, s.Value);
etor.Optimize(s.Value);
}
}
if (judge.on_hit != null) OptimizeJudgeActions(judge.on_hit, etor);
if (judge.on_miss != null) OptimizeJudgeActions(judge.on_miss, etor);
}
foreach (var a in judges.Areas) {
etor.Optimize(a.Value);
@@ -61,6 +58,9 @@ namespace Cryville.Crtr {
}
constraints.Optimize(etor);
}
void OptimizeJudgeActions(PairList<JudgeAction, PdtExpression> actions, PdtEvaluatorBase etor) {
foreach (var a in actions) a.Key.Optimize(etor, a.Value);
}
public void PrePatch(Chart chart) {
constraints.PrePatch(chart);
}
@@ -83,10 +83,32 @@ namespace Cryville.Crtr {
public PdtExpression clip;
public PdtExpression input;
public PdtExpression hit;
public PdtExpression persist; // TODO Compat
public Identifier[] pass; // TODO Compat
public Identifier[] miss; // TODO Compat
public PairList<ScoreOperation, PdtExpression> scores; // TODO Compat
public PdtExpression persist;
public PairList<JudgeAction, PdtExpression> on_hit;
public PairList<JudgeAction, PdtExpression> on_miss;
#pragma warning disable IDE1006
public PairList<ScoreOperation, PdtExpression> scores {
set {
if (on_hit == null) on_hit = new PairList<JudgeAction, PdtExpression>();
int i = 0;
foreach (var s in value) {
on_hit.Insert(i++, new JudgeAction.Score(s.Key), s.Value);
}
}
}
public Identifier[] pass {
set {
if (on_hit == null) on_hit = new PairList<JudgeAction, PdtExpression>();
on_hit.Add(new JudgeAction.Pass(Enumerable.Empty<string>(), value), PdtExpression.Empty);
}
}
public Identifier[] miss {
set {
if (on_miss == null) on_miss = new PairList<JudgeAction, PdtExpression>();
on_miss.Add(new JudgeAction.Pass(Enumerable.Empty<string>(), value), PdtExpression.Empty);
}
}
#pragma warning restore IDE1006
}
public class ScoreOperation {
public Identifier name;

View File

@@ -1,3 +1,4 @@
using Cryville.Common.Collections.Generic;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
@@ -10,11 +11,29 @@ namespace Cryville.Crtr {
readonly List<RulesetSelector> s = new List<RulesetSelector>();
readonly HashSet<string> a = new HashSet<string>();
protected override object InterpretKey(Type type) {
if (type == typeof(Constraint))
if (PairCollection<JudgeAction, PdtExpression>.IsPairCollection(type))
return InterpretJudgeAction();
else if (type == typeof(Constraint))
return InterpretConstraintKey();
else
return base.InterpretKey(type);
}
object InterpretJudgeAction() {
a.Clear();
while (true) {
int pp = Position;
switch (cc) {
case '@':
GetChar();
a.Add(GetIdentifier());
break;
default:
return JudgeAction.Construct(a, (string)base.InterpretKey(null));
}
ws();
if (Position == pp) throw new FormatException("Invalid judge action format.");
}
}
object InterpretConstraintKey() {
s.Clear(); a.Clear();
string key = "";