199 lines
6.1 KiB
C#
199 lines
6.1 KiB
C#
using Cryville.Common;
|
|
using Cryville.Common.Pdt;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace Cryville.Crtr {
|
|
public class Ruleset {
|
|
[JsonRequired]
|
|
public long format;
|
|
|
|
[JsonRequired]
|
|
public string @base;
|
|
|
|
[JsonRequired]
|
|
public string pdt;
|
|
|
|
[JsonIgnore]
|
|
public PdtRuleset Root { get; private set; }
|
|
|
|
public void LoadPdt(DirectoryInfo dir) {
|
|
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + pdt + ".pdt", Encoding.UTF8)) {
|
|
var src = pdtreader.ReadToEnd();
|
|
Root = new RulesetInterpreter(src, null).Interpret();
|
|
}
|
|
}
|
|
}
|
|
|
|
[Binder(typeof(PdtRulesetBinder))]
|
|
public class PdtRuleset {
|
|
public Dictionary<string, InputDefinition> inputs;
|
|
public Dictionary<string, JudgeDefinition> judges;
|
|
public Dictionary<string, ScoreDefinition> scores;
|
|
public Constraint constraints;
|
|
public void Optimize(PdtEvaluatorBase etor) {
|
|
foreach (var i in inputs.Values) {
|
|
if (i.pass != null) foreach (var e in i.pass.Values) {
|
|
etor.Optimize(e);
|
|
}
|
|
}
|
|
foreach (var j in judges.Values) {
|
|
if (j.clip != null) etor.Optimize(j.clip);
|
|
if (j.hit != null) etor.Optimize(j.hit);
|
|
if (j.scores != null) foreach (var e in j.scores.Values) {
|
|
etor.Optimize(e);
|
|
}
|
|
}
|
|
foreach (var s in scores.Values) {
|
|
if (s.value != null) etor.Optimize(s.value);
|
|
}
|
|
constraints.Optimize(etor);
|
|
}
|
|
public void PrePatch(Chart chart) {
|
|
constraints.PrePatch(chart);
|
|
}
|
|
}
|
|
public class Constraint {
|
|
class ArbitraryOp : PropOp {
|
|
public int name;
|
|
protected override void Execute() {
|
|
var op = GetOperand(0);
|
|
var value = new byte[op.Length];
|
|
op.CopyTo(value, 0);
|
|
ChartPlayer.etor.ContextCascadeUpdate(name, new PropSrc.Arbitrary(op.Type, value));
|
|
}
|
|
}
|
|
static readonly ArbitraryOp _arbop = new ArbitraryOp();
|
|
[ElementList]
|
|
public Dictionary<RulesetSelectors, Constraint> Elements = new Dictionary<RulesetSelectors, Constraint>();
|
|
[PropertyList]
|
|
public Dictionary<PropertyKey, PdtExpression> Properties = new Dictionary<PropertyKey, PdtExpression>();
|
|
public void Optimize(PdtEvaluatorBase etor) {
|
|
foreach (var e in Properties.Values) {
|
|
etor.Optimize(e);
|
|
}
|
|
foreach (var e in Elements) {
|
|
e.Key.Optimize(etor);
|
|
e.Value.Optimize(etor);
|
|
}
|
|
}
|
|
public void PrePatch(ChartEvent ev) {
|
|
var etor = ChartPlayer.etor;
|
|
PropSrc src;
|
|
etor.ContextCascadeInsert();
|
|
etor.ContextEvent = ev;
|
|
foreach (var prop in Properties) {
|
|
var name = prop.Key.Name;
|
|
switch (prop.Key.Type) {
|
|
case PropertyType.Property:
|
|
if (ev.PropSrcs.TryGetValue(name, out src))
|
|
etor.ContextSelfValue = src;
|
|
etor.Evaluate(ev.PropOps[name], prop.Value);
|
|
etor.ContextSelfValue = null;
|
|
break;
|
|
case PropertyType.Variable:
|
|
_arbop.name = name;
|
|
etor.Evaluate(_arbop, prop.Value);
|
|
break;
|
|
default: throw new NotSupportedException("Unknown property key type");
|
|
}
|
|
}
|
|
etor.ContextEvent = null;
|
|
foreach (var el in Elements) {
|
|
var targets = el.Key.Match(ev);
|
|
if (targets == null) continue;
|
|
foreach (var target in targets)
|
|
el.Value.PrePatch(target);
|
|
}
|
|
etor.ContextCascadeDiscard();
|
|
}
|
|
}
|
|
public class PropertyKey {
|
|
public PropertyType Type { get; private set; }
|
|
public int Name { get; private set; }
|
|
public PropertyKey(PropertyType type, string name) {
|
|
Type = type;
|
|
Name = IdentifierManager.SharedInstance.Request(name);
|
|
}
|
|
public override string ToString() {
|
|
switch (Type) {
|
|
case PropertyType.Property: return Name.ToString();
|
|
case PropertyType.Variable: return string.Format("@var {0}", Name);
|
|
default: return string.Format("<{0}> {1}", Type, Name);
|
|
}
|
|
}
|
|
}
|
|
public enum PropertyType {
|
|
Property,
|
|
Variable,
|
|
}
|
|
public class PdtRulesetBinder : EmptyBinder {
|
|
public override object ChangeType(object value, Type type, CultureInfo culture) {
|
|
if (value is PdtExpression) {
|
|
var exp = (PdtExpression)value;
|
|
if (type.Equals(typeof(bool))) {
|
|
bool result = false;
|
|
ChartPlayer.etor.Evaluate(new PropOp.Boolean(r => result = r), exp);
|
|
return result;
|
|
}
|
|
else if (type.Equals(typeof(int))) {
|
|
int result = 0;
|
|
ChartPlayer.etor.Evaluate(new PropOp.Integer(r => result = r), exp);
|
|
return result;
|
|
}
|
|
else if (type.Equals(typeof(float))) {
|
|
float result = 0;
|
|
ChartPlayer.etor.Evaluate(new PropOp.Float(r => result = r), exp);
|
|
return result;
|
|
}
|
|
else if (type.Equals(typeof(string))) {
|
|
string result = null;
|
|
ChartPlayer.etor.Evaluate(new pop_identstr(r => result = r), exp);
|
|
return result;
|
|
}
|
|
else if (type.Equals(typeof(string[]))) {
|
|
string[] result = null;
|
|
ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp);
|
|
return result;
|
|
}
|
|
}
|
|
return base.ChangeType(value, type, culture);
|
|
}
|
|
#pragma warning disable IDE1006
|
|
class pop_identstr : PropOp {
|
|
readonly Action<string> _cb;
|
|
public pop_identstr(Action<string> cb) { _cb = cb; }
|
|
protected override void Execute() {
|
|
var op = GetOperand(0);
|
|
if (op.Type == PdtInternalType.Undefined) _cb((string)IdentifierManager.SharedInstance.Retrieve(op.AsIdentifier()));
|
|
else if (op.Type == PdtInternalType.String) _cb(op.AsString());
|
|
else throw new InvalidCastException("Not an identifier or string");
|
|
}
|
|
}
|
|
class pop_identstrarr : PdtOperator {
|
|
readonly Action<string[]> _cb;
|
|
public pop_identstrarr(Action<string[]> cb) : base(16) { _cb = cb; }
|
|
protected override void Execute() {
|
|
var result = new string[LoadedOperandCount];
|
|
for (int i = 0; i < LoadedOperandCount; i++) {
|
|
var op = GetOperand(i);
|
|
if (op.Type != PdtInternalType.Undefined)
|
|
throw new InvalidCastException("Not an identifier");
|
|
result[i] = (string)IdentifierManager.SharedInstance.Retrieve(op.AsIdentifier());
|
|
}
|
|
_cb(result);
|
|
}
|
|
}
|
|
#pragma warning restore IDE1006
|
|
}
|
|
public class RulesetViolationException : Exception {
|
|
public RulesetViolationException() { }
|
|
public RulesetViolationException(string message) : base(message) { }
|
|
public RulesetViolationException(string message, Exception innerException) : base(message, innerException) { }
|
|
}
|
|
}
|