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 inputs; public Dictionary judges; public Dictionary 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 Elements = new Dictionary(); [PropertyList] public Dictionary Properties = new Dictionary(); 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 (string)IdentifierManager.SharedInstance.Retrieve(Name); case PropertyType.Variable: return string.Format("@var {0}", IdentifierManager.SharedInstance.Retrieve(Name)); default: return string.Format("<{0}> {1}", Type, IdentifierManager.SharedInstance.Retrieve(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 _cb; public pop_identstr(Action 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 _cb; public pop_identstrarr(Action 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) { } } }