Make judge functions return judge time and judge vector.

This commit is contained in:
2023-06-02 18:05:25 +08:00
parent 4d13c06f27
commit 59b4f14fb3

View File

@@ -687,49 +687,87 @@ namespace Cryville.Crtr {
_ctxcb = ctxcb;
}
protected sealed override void Execute() {
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
var fn = oputil.AsNumber(_ctxcb(_var_fn));
var tn = oputil.AsNumber(_ctxcb(_var_tn));
var ft = oputil.AsNumber(_ctxcb(_var_ft));
var tt = oputil.AsNumber(_ctxcb(_var_tt));
var fv = oputil.AsVector(_ctxcb(_var_fv));
var tv = oputil.AsVector(_ctxcb(_var_tv));
ret.SetNumber(ExecuteImpl(fn, tn, ft, tt, fv, tv));
var result = ExecuteImpl(fn, tn, ft, tt, fv, tv);
var ret = GetReturnFrame(PdtInternalType.Vector, 6 * sizeof(float) + sizeof(int));
ret.SetArraySuffix(PdtInternalType.Number);
ret.SetNumber(result.Value);
if (result.Value <= 0) return;
ret.SetNumber(result.Time, sizeof(float));
Vector4 rv;
if (result.Time == ft) {
if (!fv.HasValue) {
if (result.Time == tt) {
if (!tv.HasValue) throw new ArgumentException("Internal judge error");
rv = tv.Value;
}
else throw new ArgumentException("Internal judge error");
}
else rv = fv.Value;
}
else if (result.Time == tt) {
if (!tv.HasValue) throw new ArgumentException("Internal judge error");
rv = tv.Value;
}
else {
if (!fv.HasValue || !tv.HasValue) throw new ArgumentException("Internal judge error");
var tr = (result.Time - ft) / (tt - ft);
rv = (1 - tr) * fv.Value + tr * tv.Value;
}
for (int i = 0; i < 4; i++) {
ret.SetNumber(rv[i], (i + 2) * sizeof(float));
}
}
protected abstract JudgeFunctionResult ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv);
protected struct JudgeFunctionResult {
/// <summary>
/// The result value, represented with a signed distance or a result boolean (0 or 1.)
/// </summary>
public float Value;
public float Time;
public JudgeFunctionResult(float value, float time = 0) {
Value = value;
Time = time;
}
}
protected abstract float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv);
}
class func_attack_timing : JudgeFunction {
public func_attack_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv != null) return 0;
protected override JudgeFunctionResult ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv != null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return (tt > t0 && tt <= t1) ? 1 : 0;
return new JudgeFunctionResult((tt > t0 && tt <= t1) ? 1 : 0, tt);
}
}
class func_enter_timing : JudgeFunction {
public func_enter_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return 0;
protected override JudgeFunctionResult ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
return (ft < t0 && tt >= t0) ? 1 : 0;
return new JudgeFunctionResult((ft < t0 && tt >= t0) ? 1 : 0, t0);
}
}
class func_release_timing : JudgeFunction {
public func_release_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (tv != null) return 0;
protected override JudgeFunctionResult ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (tv != null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
return (ft > t0 && ft <= t1) ? 1 : 0;
return new JudgeFunctionResult((ft > t0 && ft <= t1) ? 1 : 0, ft);
}
}
class func_leave_timing : JudgeFunction {
public func_leave_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return 0;
protected override JudgeFunctionResult ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return new JudgeFunctionResult();
var t1 = GetOperand(0).AsNumber() + tn;
return (ft < t1 && tt >= t1) ? 1 : 0;
return new JudgeFunctionResult((ft < t1 && tt >= t1) ? 1 : 0, t1);
}
}
#endregion
@@ -741,12 +779,18 @@ namespace Cryville.Crtr {
readonly PropOp _areaOp;
Vector4 _vec;
readonly PropSrc _vecSrc;
PdtExpression _areaFunc;
public AreaJudgeFunction(int pc, Func<int, PropSrc> ctxcb, Func<int, PdtExpression> jacb, PdtEvaluator etor) : base(pc, ctxcb) {
_jacb = jacb;
_etor = etor;
_areaOp = new PropOp.Float(v => _area = v);
_vecSrc = new PropSrc.Vector4(() => _vec);
}
protected sealed override JudgeFunctionResult ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
_areaFunc = _jacb(GetOperand(2).AsIdentifier());
return ExecuteImpl2(fn, tn, ft, tt, fv, tv);
}
protected abstract JudgeFunctionResult ExecuteImpl2(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv);
protected float EvaluateArea(Vector4? vec) {
if (vec == null) {
_etor.ContextSelfValue = PropSrc.Null;
@@ -756,58 +800,64 @@ namespace Cryville.Crtr {
_vecSrc.Invalidate();
_etor.ContextSelfValue = _vecSrc;
}
_etor.Evaluate(_areaOp, _jacb(GetOperand(2).AsIdentifier()));
_etor.Evaluate(_areaOp, _areaFunc);
_etor.ContextSelfValue = null;
return _area;
}
protected bool IntersectsWithAreaBounds(Vector4 fiv, Vector4 tiv, bool enter) {
protected JudgeFunctionResult IntersectsWithAreaBounds(float ft, float tt, Vector4 fiv, Vector4 tiv, bool enter) {
for (int i = 1; i <= ChartPlayer.areaJudgePrecision; i++) {
float r = i / ChartPlayer.areaJudgePrecision;
if ((EvaluateArea((1 - r) * fiv + r * tiv) > 0) == enter) return true;
}
return false;
}
protected bool GetInternalVectors(float t0, float t1, float ft, float tt, Vector4 fv, Vector4 tv, out Vector4 fiv, out Vector4 tiv) {
var dt = tt - ft;
if (ft < t0) {
if (tt < t0) goto failed;
var fr = (t0 - ft) / dt;
fiv = (1 - fr) * fv + fr * tv;
}
else if (ft < t1) {
fiv = fv;
}
else goto failed;
if (tt < t1) tiv = tv;
else {
var tr = (t1 - ft) / dt;
tiv = (1 - tr) * fv + tr * tv;
float r = (float)i / ChartPlayer.areaJudgePrecision;
if ((EvaluateArea((1 - r) * fiv + r * tiv) > 0) == enter) {
float l = (float)(i - 1) / ChartPlayer.areaJudgePrecision;
while (!Mathf.Approximately(l, r)) {
float m = (l + r) / 2;
float v = EvaluateArea((1 - m) * fiv + m * tiv);
if (v == 0) return new JudgeFunctionResult(1, (1 - m) * ft + m * tt);
else if ((v > 0) == enter) r = m;
else l = m;
}
return new JudgeFunctionResult(1, (1 - l) * ft + l * tt);
}
}
return new JudgeFunctionResult();
}
protected bool GetInternalTimeAndVector(float t0, float t1, ref float ft, ref float tt, ref Vector4 fv, ref Vector4 tv) {
if (ft < t0) {
if (tt < t0) return false;
var fr = (t0 - ft) / (tt - ft);
ft = (1 - fr) * ft + fr * tt;
fv = (1 - fr) * fv + fr * tv;
}
else if (ft < t1) { }
else return false;
if (tt < t1) { }
else {
var tr = (t1 - ft) / (tt - ft);
tt = (1 - tr) * ft + tr * tt;
tv = (1 - tr) * fv + tr * tv;
}
return true;
failed:
fiv = tiv = default(Vector4);
return false;
}
}
class func_attack_timed_area : AreaJudgeFunction {
public func_attack_timed_area(Func<int, PropSrc> ctxcb, Func<int, PdtExpression> jacb, PdtEvaluator etor) : base(3, ctxcb, jacb, etor) { }
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv != null) return 0;
protected override JudgeFunctionResult ExecuteImpl2(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv != null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
if (tt <= t0 || tt > t1) return 0;
return EvaluateArea(tv);
if (tt <= t0 || tt > t1) return new JudgeFunctionResult();
return new JudgeFunctionResult(EvaluateArea(tv), tt);
}
}
class func_release_timed_area : AreaJudgeFunction {
public func_release_timed_area(Func<int, PropSrc> ctxcb, Func<int, PdtExpression> jacb, PdtEvaluator etor) : base(3, ctxcb, jacb, etor) { }
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (tv != null) return 0;
protected override JudgeFunctionResult ExecuteImpl2(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (tv != null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
if (ft > t0 && ft <= t1) return 0;
return EvaluateArea(fv);
if (ft > t0 && ft <= t1) return new JudgeFunctionResult();
return new JudgeFunctionResult(EvaluateArea(fv), ft);
}
}
class func_enter_or_leave_timed_area : AreaJudgeFunction {
@@ -815,14 +865,14 @@ namespace Cryville.Crtr {
public func_enter_or_leave_timed_area(Func<int, PropSrc> ctxcb, Func<int, PdtExpression> jacb, PdtEvaluator etor, bool enter) : base(3, ctxcb, jacb, etor) {
_enter = enter;
}
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return 0;
protected override JudgeFunctionResult ExecuteImpl2(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
Vector4 fiv, tiv;
if (!GetInternalVectors(t0, t1, ft, tt, fv.Value, tv.Value, out fiv, out tiv)) return 0;
if ((EvaluateArea(fiv) > 0) == _enter) return 0;
return IntersectsWithAreaBounds(fiv, tiv, _enter) ? 1 : 0;
Vector4 fiv = fv.Value, tiv = tv.Value;
if (!GetInternalTimeAndVector(t0, t1, ref ft, ref tt, ref fiv, ref tiv)) return new JudgeFunctionResult();
if ((EvaluateArea(fiv) > 0) == _enter) return new JudgeFunctionResult();
return IntersectsWithAreaBounds(ft, tt, fiv, tiv, _enter);
}
}
class func_enter_or_leave_timing_area : AreaJudgeFunction {
@@ -830,14 +880,14 @@ namespace Cryville.Crtr {
public func_enter_or_leave_timing_area(Func<int, PropSrc> ctxcb, Func<int, PdtExpression> jacb, PdtEvaluator etor, bool enter) : base(3, ctxcb, jacb, etor) {
_enter = enter;
}
protected override float ExecuteImpl(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return 0;
protected override JudgeFunctionResult ExecuteImpl2(float fn, float tn, float ft, float tt, Vector4? fv, Vector4? tv) {
if (fv == null || tv == null) return new JudgeFunctionResult();
var t0 = GetOperand(0).AsNumber() + fn;
var t1 = GetOperand(1).AsNumber() + tn;
if ((EvaluateArea(fv) > 0 && ft > t0 && ft < t1) == _enter) return 0;
Vector4 fiv, tiv;
if (!GetInternalVectors(t0, t1, ft, tt, fv.Value, tv.Value, out fiv, out tiv)) return 0;
return IntersectsWithAreaBounds(fiv, tiv, _enter) ? 1 : 0;
if ((EvaluateArea(fv) > 0 && ft > t0 && ft < t1) == _enter) return new JudgeFunctionResult();
Vector4 fiv = fv.Value, tiv = tv.Value;
if (!GetInternalTimeAndVector(t0, t1, ref ft, ref tt, ref fiv, ref tiv)) return new JudgeFunctionResult();
return IntersectsWithAreaBounds(ft, tt, fiv, tiv, _enter);
}
}
#endregion