1044 lines
41 KiB
C#
1044 lines
41 KiB
C#
using Cryville.Common;
|
|
using Cryville.Common.Collections.Specialized;
|
|
using Cryville.Common.Math;
|
|
using Cryville.Common.Pdt;
|
|
using Cryville.Crtr.Config;
|
|
using Cryville.Crtr.Event;
|
|
using Cryville.Crtr.Ruleset;
|
|
using Cryville.Crtr.Skin;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using UnityEngine;
|
|
|
|
namespace Cryville.Crtr {
|
|
public class PdtEvaluator : PdtEvaluatorBase {
|
|
static PdtEvaluator m_instance;
|
|
public static PdtEvaluator Instance {
|
|
get {
|
|
m_instance ??= new PdtEvaluator();
|
|
return m_instance;
|
|
}
|
|
}
|
|
|
|
readonly Dictionary<PdtOperatorSignature, PdtOperator> _shortops = new();
|
|
readonly IntKeyedDictionary<PdtOperator> _ctxops = new();
|
|
|
|
static readonly byte[] _nullbuf = new byte[0];
|
|
readonly byte[] _numbuf = new byte[4];
|
|
readonly PropSrc _vecsrc;
|
|
Vector _vec;
|
|
static readonly int _var_w = IdentifierManager.Shared.Request("w");
|
|
static readonly int _var_h = IdentifierManager.Shared.Request("h");
|
|
static readonly int _var_inf = IdentifierManager.Shared.Request("inf");
|
|
static readonly int _var_true = IdentifierManager.Shared.Request("true");
|
|
static readonly int _var_false = IdentifierManager.Shared.Request("false");
|
|
static readonly int _var_null = IdentifierManager.Shared.Request("null");
|
|
static readonly int _var_current_time = IdentifierManager.Shared.Request("current_time");
|
|
protected override void GetVariable(int name, bool forced, out int type, out byte[] value) {
|
|
if (name == _var_w) { LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; }
|
|
else if (name == _var_h) { LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; }
|
|
else if (name == _var_inf) { LoadNum(float.PositiveInfinity); type = PdtInternalType.Number; value = _numbuf; }
|
|
else if (name == _var_true) { LoadNum(1); type = PdtInternalType.Number; value = _numbuf; }
|
|
else if (name == _var_false) { LoadNum(0); type = PdtInternalType.Number; value = _numbuf; }
|
|
else if (name == _var_null) { LoadIdent(0); type = PdtInternalType.Undefined; value = _numbuf; }
|
|
else {
|
|
if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out PropSrc prop)) {
|
|
prop.Get(out type, out value);
|
|
}
|
|
else if (ContextState != null && ChartPlayer.motionRegistry.ContainsKey(new Identifier(name))) {
|
|
_vec = ContextState.GetComputedValue(name);
|
|
_vecsrc.Invalidate();
|
|
_vecsrc.Get(out type, out value);
|
|
RevokePotentialConstant();
|
|
}
|
|
else if (ContextState != null && ContextState.Handler.PropSrcs.TryGetValue(name, out prop)) {
|
|
prop.Get(out type, out value);
|
|
RevokePotentialConstant();
|
|
}
|
|
else if (ContextSkinContainer != null && ContextSkinContainer.Variables.TryGetValue(name, out PropStores.Float variable)) {
|
|
variable.Source.Get(out type, out value);
|
|
}
|
|
else if (ContextRulesetConfig != null && ContextRulesetConfig.TryGetMappedSource(name, out prop)) {
|
|
prop.Get(out type, out value);
|
|
}
|
|
else if (ContextJudge != null && ContextJudge.TryGetScoreSrc(name, out prop)) {
|
|
prop.Get(out type, out value);
|
|
RevokePotentialConstant();
|
|
}
|
|
else {
|
|
PropSrc result = ContextCascadeLookup(name);
|
|
if (result != null) {
|
|
result.Get(out type, out value);
|
|
}
|
|
else if (forced) {
|
|
type = PdtInternalType.Error;
|
|
value = _nullbuf;
|
|
}
|
|
else {
|
|
type = PdtInternalType.Undefined;
|
|
LoadIdent(name);
|
|
value = _numbuf;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
unsafe void LoadIdent(int value) {
|
|
fixed (byte* ptr = _numbuf) *(int*)ptr = value;
|
|
}
|
|
unsafe void LoadNum(float value) {
|
|
fixed (byte* ptr = _numbuf) *(float*)ptr = value;
|
|
}
|
|
static readonly int _op_sep = IdentifierManager.Shared.Request(",");
|
|
static readonly int _func_int_map = IdentifierManager.Shared.Request("int_map");
|
|
static readonly int _func_map = IdentifierManager.Shared.Request("map");
|
|
protected override PdtOperator GetOperator(PdtOperatorSignature sig) {
|
|
if (_shortops.TryGetValue(sig, out PdtOperator result)) {
|
|
return result;
|
|
}
|
|
else if (_ctxops.TryGetValue(sig.Name, out result)) {
|
|
return result;
|
|
}
|
|
else if (sig.Name == _op_sep) {
|
|
result = new op_arr(sig.ParamCount);
|
|
_shortops.Add(new PdtOperatorSignature(_op_sep, sig.ParamCount), result);
|
|
return result;
|
|
}
|
|
else if (sig.Name == _func_int_map) {
|
|
result = new func_int_map(sig.ParamCount);
|
|
_shortops.Add(new PdtOperatorSignature(_func_int_map, sig.ParamCount), result);
|
|
return result;
|
|
}
|
|
else if (sig.Name == _func_map) {
|
|
result = new func_map(sig.ParamCount);
|
|
_shortops.Add(new PdtOperatorSignature(_func_map, sig.ParamCount), result);
|
|
return result;
|
|
}
|
|
else throw new KeyNotFoundException(string.Format("Undefined operator {0}", sig));
|
|
}
|
|
|
|
static readonly int _colop_and = IdentifierManager.Shared.Request("&");
|
|
static readonly int _colop_or = IdentifierManager.Shared.Request("|");
|
|
protected override bool Collapse(int name, PdtVariableMemory param) {
|
|
if (name == _colop_and) return (param.Type == PdtInternalType.Number || param.Type == PdtInternalType.Vector) && param.AsNumber() <= 0;
|
|
else if (name == _colop_or) return (param.Type != PdtInternalType.Number && param.Type != PdtInternalType.Vector) || param.AsNumber() > 0;
|
|
else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", IdentifierManager.Shared.Retrieve(name)));
|
|
}
|
|
|
|
public ChartEvent ContextEvent { get; set; }
|
|
public ContainerState ContextState { get; set; }
|
|
public SkinContainer ContextSkinContainer { get; set; }
|
|
public Transform ContextTransform { get; set; }
|
|
public RulesetConfigStore ContextRulesetConfig { get; set; }
|
|
public Judge ContextJudge { get; set; }
|
|
public PropSrc ContextSelfValue { get; set; }
|
|
|
|
readonly Stack<int> ContextCascadeBlocks = new();
|
|
public void ContextCascadeInsertBlock() {
|
|
ContextCascadeBlocks.Push(_cascadeHeight);
|
|
}
|
|
public void ContextCascadeDiscardBlock() {
|
|
ContextCascadeBlocks.Pop();
|
|
}
|
|
readonly IntKeyedDictionary<PropSrc>[] ContextCascade = new IntKeyedDictionary<PropSrc>[256];
|
|
int _cascadeHeight;
|
|
public void ContextCascadeInsert() {
|
|
_cascadeHeight++;
|
|
}
|
|
public void ContextCascadeInsert(IntKeyedDictionary<PropSrc> srcs) {
|
|
ContextCascadeInsert();
|
|
foreach (var src in srcs) ContextCascadeUpdate(src.Key, src.Value);
|
|
}
|
|
public void ContextCascadeUpdate(int key, PropSrc value) {
|
|
ContextCascade[_cascadeHeight - 1][key] = value;
|
|
}
|
|
public PropSrc ContextCascadeLookup(int name) {
|
|
for (int i = _cascadeHeight - 1; i >= ContextCascadeBlocks.Peek(); i--) {
|
|
var cas = ContextCascade[i];
|
|
if (cas.TryGetValue(name, out PropSrc result)) {
|
|
return result;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
public void ContextCascadeDiscard() {
|
|
ContextCascade[--_cascadeHeight].Clear();
|
|
}
|
|
|
|
public void Reset() {
|
|
_cascadeHeight = 0;
|
|
ContextCascadeBlocks.Clear();
|
|
ContextCascadeBlocks.Push(0);
|
|
ContextEvent = null;
|
|
ContextJudge = null;
|
|
ContextRulesetConfig = null;
|
|
ContextSelfValue = null;
|
|
ContextSkinContainer = null;
|
|
ContextState = null;
|
|
ContextTransform = null;
|
|
}
|
|
|
|
public PdtEvaluator() {
|
|
ContextCascadeBlocks.Push(0);
|
|
for (int i = 0; i < ContextCascade.Length; i++) ContextCascade[i] = new IntKeyedDictionary<PropSrc>();
|
|
_vecsrc = new VectorSrc(() => _vec);
|
|
|
|
_shortops.Add(new PdtOperatorSignature("@", 2), new op_at_2());
|
|
|
|
_shortops.Add(new PdtOperatorSignature("*", 2), new op_mul_2());
|
|
_shortops.Add(new PdtOperatorSignature("/", 2), new op_div_2());
|
|
_shortops.Add(new PdtOperatorSignature("%", 2), new op_mod_2());
|
|
|
|
_shortops.Add(new PdtOperatorSignature("+", 1), new op_add_1());
|
|
_shortops.Add(new PdtOperatorSignature("+", 2), new op_add_2());
|
|
_shortops.Add(new PdtOperatorSignature("-", 1), new op_sub_1());
|
|
_shortops.Add(new PdtOperatorSignature("-", 2), new op_sub_2());
|
|
|
|
_shortops.Add(new PdtOperatorSignature("=", 2), new op_eq_2());
|
|
_shortops.Add(new PdtOperatorSignature("<", 2), new op_lt_2());
|
|
_shortops.Add(new PdtOperatorSignature(">", 2), new op_gt_2());
|
|
|
|
_shortops.Add(new PdtOperatorSignature("!", 1), new op_not_1());
|
|
|
|
_shortops.Add(new PdtOperatorSignature("frame_seq", 3), new func_frame_seq());
|
|
_shortops.Add(new PdtOperatorSignature("is", 2), new func_is());
|
|
_shortops.Add(new PdtOperatorSignature("is_in", 1), new func_is_in());
|
|
|
|
_ctxops.Add(IdentifierManager.Shared.Request("screen_edge"), new func_screen_edge(() => ContextTransform));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("int"), new func_int(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("clamp"), new func_clamp(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("min"), new func_min(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("max"), new func_max(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("abs"), new func_abs(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("anim"), new func_anim(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("cubic_bezier"), new func_cubic_bezier(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("ease"), new func_cubic_bezier_fixed(0.25f, 0.1f, 0.25f, 1f, () => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("ease_in"), new func_cubic_bezier_fixed(0.42f, 0f, 1f, 1f, () => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("ease_out"), new func_cubic_bezier_fixed(0f, 0f, 0.58f, 1f, () => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("ease_in_out"), new func_cubic_bezier_fixed(0.42f, 0f, 0.58f, 1f, () => ContextSelfValue));
|
|
|
|
_ctxops.Add(IdentifierManager.Shared.Request("precision"), new func_precision(() => ContextSelfValue));
|
|
|
|
_ctxops.Add(IdentifierManager.Shared.Request("interval"), new func_interval(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("circle"), new func_sphere(() => ContextSelfValue));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("sphere"), new func_sphere(() => ContextSelfValue));
|
|
|
|
PropSrc cccb(int k) => ContextCascadeLookup(k);
|
|
_ctxops.Add(IdentifierManager.Shared.Request("attack_timing"), new func_attack_timing(cccb));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("release_timing"), new func_release_timing(cccb));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("enter_timing"), new func_enter_timing(cccb));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("leave_timing"), new func_leave_timing(cccb));
|
|
|
|
PdtExpression jacb(int k) => ContextJudge._areaFuncs[new Identifier(k)];
|
|
_ctxops.Add(IdentifierManager.Shared.Request("attack_timed_area"), new func_attack_timed_area(cccb, jacb, this));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("release_timed_area"), new func_release_timed_area(cccb, jacb, this));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("enter_timed_area"), new func_enter_or_leave_timed_area(cccb, jacb, this, true));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("leave_timed_area"), new func_enter_or_leave_timed_area(cccb, jacb, this, false));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("enter_timing_area"), new func_enter_or_leave_timing_area(cccb, jacb, this, true));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("leave_timing_area"), new func_enter_or_leave_timing_area(cccb, jacb, this, false));
|
|
|
|
_ctxops.Add(IdentifierManager.Shared.Request("in_timing"), new func_in_timing(cccb));
|
|
_ctxops.Add(IdentifierManager.Shared.Request("in_area"), new func_in_area(cccb, jacb, this));
|
|
}
|
|
#region Operators
|
|
#pragma warning disable IDE1006
|
|
#region Basic Operators
|
|
class op_add_1 : PdtOperator {
|
|
public op_add_1() : base(1) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_add_2 : PdtOperator {
|
|
public op_add_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() + GetOperand(1).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_sub_1 : PdtOperator {
|
|
public op_sub_1() : base(1) { }
|
|
protected override void Execute() {
|
|
float result = -GetOperand(0).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_sub_2 : PdtOperator {
|
|
public op_sub_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() - GetOperand(1).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_mul_2 : PdtOperator {
|
|
public op_mul_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() * GetOperand(1).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_div_2 : PdtOperator {
|
|
public op_div_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() / GetOperand(1).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_mod_2 : PdtOperator {
|
|
public op_mod_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() % GetOperand(1).AsNumber();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_eq_2 : PdtOperator {
|
|
public op_eq_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() == GetOperand(1).AsNumber() ? 1 : 0;
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_lt_2 : PdtOperator {
|
|
public op_lt_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() < GetOperand(1).AsNumber() ? 1 : 0;
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_gt_2 : PdtOperator {
|
|
public op_gt_2() : base(2) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() > GetOperand(1).AsNumber() ? 1 : 0;
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_not_1 : PdtOperator {
|
|
public op_not_1() : base(1) { }
|
|
protected override void Execute() {
|
|
float result = GetOperand(0).AsNumber() <= 0 ? 1 : 0;
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
|
|
}
|
|
}
|
|
class op_arr : PdtOperator {
|
|
public op_arr(int pc) : base(pc) { }
|
|
protected override void Execute() {
|
|
var o0 = GetOperand(0);
|
|
int type = o0.Type;
|
|
int len = o0.Length;
|
|
bool blit = !IsBlittable(type);
|
|
for (var i = 1; i < LoadedOperandCount; i++) {
|
|
var o = GetOperand(i);
|
|
if (o.Type != type) throw new InvalidOperationException("Cannot create variant type array");
|
|
else if (!IsBlittable(o.Type)) blit = true;
|
|
len += o.Length;
|
|
}
|
|
if (blit) GetReturnFrame(PdtInternalType.Array, len + 2 * sizeof(int)).SetArraySuffix(type, LoadedOperandCount);
|
|
else GetReturnFrame(PdtInternalType.Vector, len + sizeof(int)).SetArraySuffix(type);
|
|
}
|
|
static bool IsBlittable(int type) {
|
|
return type == PdtInternalType.Number;
|
|
}
|
|
}
|
|
class op_at_2 : PdtOperator {
|
|
public op_at_2() : base(2) { }
|
|
protected override void Execute() {
|
|
int _;
|
|
var op0 = GetOperand(0);
|
|
var op1 = (int)Math.Round(GetOperand(1).AsNumber());
|
|
if (op0.Type == PdtInternalType.Vector) {
|
|
op0.GetArraySuffix(out _, out _);
|
|
if (op1 >= (op0.Length - sizeof(int)) / sizeof(float)) throw new IndexOutOfRangeException();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(op0.AsNumber(op1 * sizeof(float)));
|
|
}
|
|
else if (op0.Type == PdtInternalType.Number) {
|
|
if (op1 != 0) throw new IndexOutOfRangeException();
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(op0.AsNumber());
|
|
}
|
|
else throw new InvalidOperationException("Not a vector or number");
|
|
}
|
|
}
|
|
#endregion
|
|
#region Basic Functions
|
|
class func_frame_seq : PdtOperator {
|
|
public func_frame_seq() : base(3) { }
|
|
protected override unsafe void Execute() {
|
|
string pf = GetOperand(0).AsString();
|
|
int f = (int)GetOperand(1).AsNumber();
|
|
int t = (int)GetOperand(2).AsNumber();
|
|
int pfl = pf.Length;
|
|
int fc = t - f + 1;
|
|
if (fc <= 0) throw new ArgumentException("Start index is greater than end index");
|
|
int l = (f == 0 ? 1 : 0) + pfl * fc;
|
|
for (int p = 1, i = 1; p < 4; p++, i *= 10) {
|
|
int j = i * 10 - 1;
|
|
if (f <= j && t >= i) {
|
|
int m = Math.Max(f, i);
|
|
int n = Math.Min(t, j);
|
|
l += (n - m + 1) * i;
|
|
}
|
|
}
|
|
l *= sizeof(char);
|
|
l += sizeof(int) * (fc + 2);
|
|
var ret = GetReturnFrame(PdtInternalType.Array, l);
|
|
ret.SetArraySuffix(PdtInternalType.String, fc);
|
|
int o = 0;
|
|
for (int i = f; i <= t; i++) {
|
|
var s = pf + i.ToString(CultureInfo.InvariantCulture);
|
|
ret.SetString(s, o);
|
|
o += sizeof(int) + s.Length * sizeof(char);
|
|
}
|
|
}
|
|
}
|
|
class func_int_map : PdtOperator {
|
|
public func_int_map(int pc) : base(pc) {
|
|
if (pc < 4) throw new ArgumentOutOfRangeException("Too few parameters for int_map");
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var value = GetOperand(0).AsNumber();
|
|
var offset = GetOperand(1).AsNumber();
|
|
var step = GetOperand(2).AsNumber();
|
|
var index = (int)((value - offset) / step);
|
|
if (index < 0 || index >= LoadedOperandCount - 3) index = 0;
|
|
var hit = GetOperand(index + 3);
|
|
var ret = GetReturnFrame(hit.Type, hit.Length);
|
|
hit.CopyTo(ret);
|
|
}
|
|
}
|
|
class func_is : PdtOperator {
|
|
public func_is() : base(2) { }
|
|
protected override unsafe void Execute() {
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float))
|
|
.SetNumber(GetOperand(0).Equals(GetOperand(1)) ? 1 : 0);
|
|
}
|
|
}
|
|
class func_is_in : PdtOperator {
|
|
public func_is_in() : base(1) { }
|
|
protected override unsafe void Execute() {
|
|
var arg = GetOperand(0);
|
|
if (arg.Type == PdtInternalType.Number && arg.AsNumber() <= 0) {
|
|
GetReturnFrame(PdtInternalType.Null, 0);
|
|
}
|
|
else {
|
|
var ret = GetReturnFrame(arg.Type, arg.Length);
|
|
arg.CopyTo(ret);
|
|
}
|
|
}
|
|
}
|
|
class func_map : PdtOperator {
|
|
public func_map(int pc) : base(pc) {
|
|
if (pc < 2) throw new ArgumentOutOfRangeException("Too few parameters for map");
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var value = GetOperand(0).AsNumber();
|
|
var index = (int)value;
|
|
if (index < 0 || index >= LoadedOperandCount - 1) index = 0;
|
|
var hit = GetOperand(index + 1);
|
|
var ret = GetReturnFrame(hit.Type, hit.Length);
|
|
hit.CopyTo(ret);
|
|
}
|
|
}
|
|
#endregion
|
|
#region Contextual Functions
|
|
class func_screen_edge : PdtOperator {
|
|
readonly Func<Transform> _ctxcb;
|
|
public func_screen_edge(Func<Transform> ctxcb) : base(1) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var ctx = _ctxcb();
|
|
var ray = new Ray(ctx.position, ctx.rotation * Vector3.forward);
|
|
ChartPlayer.frustumPlanes[(int)GetOperand(0).AsNumber()].Raycast(ray, out float dist);
|
|
var ret = GetReturnFrame(PdtInternalType.Vector, sizeof(Vector3) + sizeof(int));
|
|
ret.Set(ray.GetPoint(dist));
|
|
ret.SetArraySuffix(PdtInternalType.Number);
|
|
}
|
|
}
|
|
class func_int : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_int(Func<PropSrc> ctxcb) : base(1) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
var v = LoadedOperandCount switch {
|
|
0 => oputil.AsNumber(_ctxcb()),
|
|
1 => GetOperand(0).AsNumber(),
|
|
_ => throw new ArgumentException("Argument count not 0 or 1"),
|
|
};
|
|
ret.SetNumber(Mathf.Floor(v));
|
|
}
|
|
}
|
|
class func_clamp : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_clamp(Func<PropSrc> ctxcb) : base(3) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
float min, value, max;
|
|
switch (LoadedOperandCount) {
|
|
case 2:
|
|
value = oputil.AsNumber(_ctxcb());
|
|
min = GetOperand(0).AsNumber();
|
|
max = GetOperand(1).AsNumber();
|
|
break;
|
|
case 3:
|
|
value = GetOperand(0).AsNumber();
|
|
min = GetOperand(1).AsNumber();
|
|
max = GetOperand(2).AsNumber();
|
|
break;
|
|
default: throw new ArgumentException("Argument count not 2 or 3");
|
|
}
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
ret.SetNumber(Mathf.Clamp(value, min, max));
|
|
}
|
|
}
|
|
class func_min : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_min(Func<PropSrc> ctxcb) : base(2) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
float a = GetOperand(0).AsNumber();
|
|
var b = LoadedOperandCount switch {
|
|
1 => oputil.AsNumber(_ctxcb()),
|
|
2 => GetOperand(1).AsNumber(),
|
|
_ => throw new ArgumentException("Argument count not 2 or 3"),
|
|
};
|
|
ret.SetNumber(Mathf.Min(a, b));
|
|
}
|
|
}
|
|
class func_max : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_max(Func<PropSrc> ctxcb) : base(2) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
var a = GetOperand(0).AsNumber();
|
|
var b = LoadedOperandCount switch {
|
|
1 => oputil.AsNumber(_ctxcb()),
|
|
2 => GetOperand(1).AsNumber(),
|
|
_ => throw new ArgumentException("Argument count not 2 or 3"),
|
|
};
|
|
ret.SetNumber(Mathf.Max(a, b));
|
|
}
|
|
}
|
|
class func_abs : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_abs(Func<PropSrc> ctxcb) : base(1) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
var arg = LoadedOperandCount switch {
|
|
0 => oputil.AsNumber(_ctxcb()),
|
|
1 => GetOperand(0).AsNumber(),
|
|
_ => throw new ArgumentException("Argument count not 0 or 1"),
|
|
};
|
|
ret.SetNumber(Mathf.Abs(arg));
|
|
}
|
|
}
|
|
class func_anim : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_anim(Func<PropSrc> ctxcb) : base(3) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var op1 = GetOperand(0);
|
|
var op2 = GetOperand(1);
|
|
var dim1 = GetDimension(op1);
|
|
var dim2 = GetDimension(op2);
|
|
var dim0 = Math.Min(dim1, dim2);
|
|
Vector4 trans;
|
|
switch (LoadedOperandCount) {
|
|
case 2:
|
|
var num = oputil.AsNumber(_ctxcb());
|
|
trans = new Vector4(num, num, num, num);
|
|
break;
|
|
case 3: trans = GetTransition(GetOperand(2)); break;
|
|
default: throw new ArgumentException("Argument count not 2 or 3");
|
|
}
|
|
if (dim0 == 1) {
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float))
|
|
.SetNumber(op1.AsNumber() * (1 - trans.x) + op2.AsNumber() * trans.x);
|
|
}
|
|
else {
|
|
var ret = GetReturnFrame(PdtInternalType.Vector, dim0 * sizeof(float) + sizeof(int));
|
|
for (int i = 0; i < dim0 * sizeof(float); i += sizeof(float)) {
|
|
ret.SetNumber(op1.AsNumber(i) * (1 - trans[i]) + op2.AsNumber(i) * trans[i], i);
|
|
}
|
|
ret.SetArraySuffix(PdtInternalType.Number);
|
|
}
|
|
}
|
|
static int GetDimension(PdtVariableMemory op) {
|
|
switch (op.Type) {
|
|
case PdtInternalType.Number: return 1;
|
|
case PdtInternalType.Vector:
|
|
int arrtype, _;
|
|
op.GetArraySuffix(out arrtype, out _);
|
|
if (arrtype != PdtInternalType.Number)
|
|
throw new ArgumentException("Not animatable");
|
|
return (op.Length - sizeof(int)) / sizeof(float);
|
|
default: throw new ArgumentException("Not animatable");
|
|
}
|
|
}
|
|
static Vector4 GetTransition(PdtVariableMemory op) {
|
|
switch (op.Type) {
|
|
case PdtInternalType.Number:
|
|
var num = op.AsNumber();
|
|
return new Vector4(num, num, num, num);
|
|
case PdtInternalType.Vector:
|
|
int arrtype, _;
|
|
op.GetArraySuffix(out arrtype, out _);
|
|
if (arrtype != PdtInternalType.Number)
|
|
throw new ArgumentException("Not animatable");
|
|
switch ((op.Length - sizeof(int)) / sizeof(float)) {
|
|
case 0: throw new ArgumentException("Empty vector");
|
|
case 1:
|
|
num = op.AsNumber();
|
|
return new Vector4(num, num, num, num);
|
|
case 2: return new Vector4(op.AsNumber(), op.AsNumber(sizeof(float)), 0, 0);
|
|
case 3: return new Vector4(op.AsNumber(), op.AsNumber(sizeof(float)), op.AsNumber(2 * sizeof(float)), 0);
|
|
default: return new Vector4(op.AsNumber(), op.AsNumber(sizeof(float)), op.AsNumber(2 * sizeof(float)), op.AsNumber(3 * sizeof(float)));
|
|
}
|
|
default: throw new ArgumentException("Not animatable");
|
|
}
|
|
}
|
|
}
|
|
class func_cubic_bezier : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_cubic_bezier(Func<PropSrc> ctxcb) : base(5) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
float x1 = GetOperand(0).AsNumber(), y1 = GetOperand(1).AsNumber();
|
|
float x2 = GetOperand(2).AsNumber(), y2 = GetOperand(3).AsNumber();
|
|
var time = LoadedOperandCount switch {
|
|
4 => oputil.AsNumber(_ctxcb()),
|
|
5 => GetOperand(4).AsNumber(),
|
|
_ => throw new ArgumentException("Argument count not 4 or 5"),
|
|
};
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float))
|
|
.SetNumber(CubicBezier.Evaluate(time, x1, y1, x2, y2, 1e-3f));
|
|
}
|
|
}
|
|
class func_cubic_bezier_fixed : PdtOperator {
|
|
readonly float x1, y1, x2, y2;
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_cubic_bezier_fixed(float x1, float y1, float x2, float y2, Func<PropSrc> ctxcb) : base(1) {
|
|
this.x1 = x1; this.y1 = y1;
|
|
this.x2 = x2; this.y2 = y2;
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override void Execute() {
|
|
var time = LoadedOperandCount switch {
|
|
0 => oputil.AsNumber(_ctxcb()),
|
|
1 => GetOperand(0).AsNumber(),
|
|
_ => throw new ArgumentException("Argument count not 0 or 1"),
|
|
};
|
|
GetReturnFrame(PdtInternalType.Number, sizeof(float))
|
|
.SetNumber(CubicBezier.Evaluate(time, x1, y1, x2, y2, 1e-3f));
|
|
}
|
|
}
|
|
class func_precision : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_precision(Func<PropSrc> ctxcb) : base(2) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected override unsafe void Execute() {
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
float v, p;
|
|
switch (LoadedOperandCount) {
|
|
case 1:
|
|
v = oputil.AsNumber(_ctxcb());
|
|
p = GetOperand(0).AsNumber(); break;
|
|
case 2:
|
|
v = GetOperand(0).AsNumber();
|
|
p = GetOperand(1).AsNumber(); break;
|
|
default: throw new ArgumentException("Argument count not 1 or 2");
|
|
}
|
|
double pp = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(p))) + 1);
|
|
double dp = pp * Math.Round(p / pp, 7);
|
|
ret.SetNumber((float)(Math.Round((double)v / dp) * dp));
|
|
}
|
|
}
|
|
#endregion
|
|
#region Area Functions
|
|
class func_interval : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_interval(Func<PropSrc> ctxcb) : base(3) { _ctxcb = ctxcb; }
|
|
protected override unsafe void Execute() {
|
|
float min, value, max;
|
|
switch (LoadedOperandCount) {
|
|
case 2:
|
|
value = oputil.AsNumber(_ctxcb());
|
|
min = GetOperand(0).AsNumber();
|
|
max = GetOperand(1).AsNumber();
|
|
break;
|
|
case 3:
|
|
value = GetOperand(0).AsNumber();
|
|
min = GetOperand(1).AsNumber();
|
|
max = GetOperand(2).AsNumber();
|
|
break;
|
|
default: throw new ArgumentException("Argument count not 2 or 3");
|
|
}
|
|
float center = (max + min) / 2;
|
|
float extent = (max - min) / 2;
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
ret.SetNumber(1 - Math.Abs(value - center) / extent);
|
|
}
|
|
}
|
|
class func_sphere : PdtOperator {
|
|
readonly Func<PropSrc> _ctxcb;
|
|
public func_sphere(Func<PropSrc> ctxcb) : base(3) { _ctxcb = ctxcb; }
|
|
protected override unsafe void Execute() {
|
|
Vector4? value, center;
|
|
float radius;
|
|
switch (LoadedOperandCount) {
|
|
case 2:
|
|
value = oputil.AsVector(_ctxcb());
|
|
center = oputil.AsVector(GetOperand(0));
|
|
radius = GetOperand(1).AsNumber();
|
|
break;
|
|
case 3:
|
|
value = oputil.AsVector(GetOperand(0));
|
|
center = oputil.AsVector(GetOperand(1));
|
|
radius = GetOperand(2).AsNumber();
|
|
break;
|
|
default: throw new ArgumentException("Argument count not 2 or 3");
|
|
}
|
|
if (value == null) {
|
|
GetReturnFrame(PdtInternalType.Null, 0);
|
|
return;
|
|
}
|
|
if (center == null) throw new ArgumentException("Null sphere center");
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
ret.SetNumber(1 - Vector4.Distance(center.Value, value.Value) / radius);
|
|
}
|
|
}
|
|
#endregion
|
|
#region Judge Functions
|
|
#region Primary
|
|
static readonly int _var_fn = IdentifierManager.Shared.Request("judge_time_from");
|
|
static readonly int _var_tn = IdentifierManager.Shared.Request("judge_time_to");
|
|
static readonly int _var_ft = IdentifierManager.Shared.Request("input_time_from");
|
|
static readonly int _var_tt = IdentifierManager.Shared.Request("input_time_to");
|
|
static readonly int _var_fv = IdentifierManager.Shared.Request("input_vec_from");
|
|
static readonly int _var_tv = IdentifierManager.Shared.Request("input_vec_to");
|
|
abstract class JudgeFunction : PdtOperator {
|
|
readonly Func<int, PropSrc> _ctxcb;
|
|
protected JudgeFunction(int pc, Func<int, PropSrc> ctxcb) : base(pc) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected sealed override void Execute() {
|
|
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));
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
#region Timing
|
|
class func_attack_timing : JudgeFunction {
|
|
public func_attack_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
|
|
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 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 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 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 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 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 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 new JudgeFunctionResult((ft < t1 && tt >= t1) ? 1 : 0, t1);
|
|
}
|
|
}
|
|
#endregion
|
|
#region Timed Area / Timing Area
|
|
abstract class AreaJudgeFunction : JudgeFunction {
|
|
readonly Func<int, PdtExpression> _jacb;
|
|
readonly PdtEvaluator _etor;
|
|
float _area;
|
|
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;
|
|
}
|
|
else {
|
|
_vec = vec.Value;
|
|
_vecSrc.Invalidate();
|
|
_etor.ContextSelfValue = _vecSrc;
|
|
}
|
|
_etor.Evaluate(_areaOp, _areaFunc);
|
|
_etor.ContextSelfValue = null;
|
|
return _area;
|
|
}
|
|
protected JudgeFunctionResult IntersectsWithAreaBounds(float ft, float tt, Vector4 fiv, Vector4 tiv, bool enter) {
|
|
for (int i = 1; i <= ChartPlayer.areaJudgePrecision; i++) {
|
|
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;
|
|
}
|
|
}
|
|
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 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 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 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 new JudgeFunctionResult();
|
|
return new JudgeFunctionResult(EvaluateArea(fv), ft);
|
|
}
|
|
}
|
|
class func_enter_or_leave_timed_area : AreaJudgeFunction {
|
|
readonly bool _enter;
|
|
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 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 = 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 {
|
|
readonly bool _enter;
|
|
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 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 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
|
|
#endregion
|
|
#region Secondary
|
|
static readonly int _var_jt = IdentifierManager.Shared.Request("hit_time");
|
|
static readonly int _var_jv = IdentifierManager.Shared.Request("hit_vec");
|
|
class func_in_timing : PdtOperator {
|
|
readonly Func<int, PropSrc> _ctxcb;
|
|
public func_in_timing(Func<int, PropSrc> ctxcb) : base(2) {
|
|
_ctxcb = ctxcb;
|
|
}
|
|
protected sealed override void Execute() {
|
|
var fn = oputil.AsNumber(_ctxcb(_var_fn));
|
|
var tn = oputil.AsNumber(_ctxcb(_var_tn));
|
|
var t0 = GetOperand(0).AsNumber() + fn;
|
|
var t1 = GetOperand(1).AsNumber() + tn;
|
|
var jt = oputil.AsNumber(_ctxcb(_var_jt));
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
ret.SetNumber((jt > t0 && jt <= t1) ? 1 : 0);
|
|
}
|
|
}
|
|
class func_in_area : PdtOperator {
|
|
readonly Func<int, PropSrc> _ctxcb;
|
|
readonly Func<int, PdtExpression> _jacb;
|
|
readonly PdtEvaluator _etor;
|
|
float _area;
|
|
readonly PropOp _areaOp;
|
|
Vector4 _vec;
|
|
readonly PropSrc _vecSrc;
|
|
public func_in_area(Func<int, PropSrc> ctxcb, Func<int, PdtExpression> jacb, PdtEvaluator etor) : base(2) {
|
|
_ctxcb = ctxcb;
|
|
_jacb = jacb;
|
|
_etor = etor;
|
|
_areaOp = new PropOp.Float(v => _area = v);
|
|
_vecSrc = new PropSrc.Vector4(() => _vec);
|
|
}
|
|
protected sealed override void Execute() {
|
|
var jv = oputil.AsVector(_ctxcb(_var_jv));
|
|
if (jv == null) {
|
|
_etor.ContextSelfValue = PropSrc.Null;
|
|
}
|
|
else {
|
|
_vec = jv.Value;
|
|
_vecSrc.Invalidate();
|
|
_etor.ContextSelfValue = _vecSrc;
|
|
}
|
|
_etor.Evaluate(_areaOp, _jacb(GetOperand(0).AsIdentifier()));
|
|
_etor.ContextSelfValue = null;
|
|
var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
|
|
ret.SetNumber(_area);
|
|
}
|
|
}
|
|
#endregion
|
|
#endregion
|
|
static unsafe class oputil {
|
|
public static float AsNumber(PropSrc src) {
|
|
if (src == null) throw new ArgumentNullException("src");
|
|
src.Get(out int type, out byte[] value);
|
|
if (type != PdtInternalType.Number && type != PdtInternalType.Vector)
|
|
throw new ArgumentException("Not a number");
|
|
fixed (byte* ptr = value) {
|
|
return *(float*)ptr;
|
|
}
|
|
}
|
|
public static Vector4? AsVector(PropSrc src) {
|
|
if (src == null) throw new ArgumentNullException("src");
|
|
src.Get(out int type, out byte[] value);
|
|
if (type == PdtInternalType.Vector) {
|
|
fixed (byte* ptr = value) {
|
|
return *(Vector4*)ptr;
|
|
}
|
|
}
|
|
else if (type == PdtInternalType.Number) {
|
|
fixed (byte* ptr = value) {
|
|
return new Vector4(*(float*)ptr, 0, 0, 0);
|
|
}
|
|
}
|
|
else if (type == PdtInternalType.Null) {
|
|
return null;
|
|
}
|
|
else throw new ArgumentException("Not a vector");
|
|
}
|
|
public static Vector4? AsVector(PdtVariableMemory op) {
|
|
if (op.Type == PdtInternalType.Vector) {
|
|
return ((op.Length - sizeof(int)) / sizeof(float)) switch {
|
|
0 => null,
|
|
1 => (Vector4?)new Vector4(op.AsNumber(), 0, 0, 0),
|
|
2 => (Vector4?)new Vector4(op.AsNumber(), op.AsNumber(sizeof(float)), 0, 0),
|
|
3 => (Vector4?)new Vector4(op.AsNumber(), op.AsNumber(sizeof(float)), op.AsNumber(2 * sizeof(float)), 0),
|
|
_ => (Vector4?)new Vector4(op.AsNumber(), op.AsNumber(sizeof(float)), op.AsNumber(2 * sizeof(float)), op.AsNumber(3 * sizeof(float))),
|
|
};
|
|
}
|
|
else if (op.Type == PdtInternalType.Number) {
|
|
return new Vector4(op.AsNumber(), 0, 0, 0);
|
|
}
|
|
else if (op.Type == PdtInternalType.Null) {
|
|
return null;
|
|
}
|
|
else throw new ArgumentException("Not a vector");
|
|
}
|
|
}
|
|
#pragma warning restore IDE1006
|
|
#endregion
|
|
}
|
|
}
|