using Cryville.Common; using Cryville.Common.Pdt; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Linq; using System; using System.Text.RegularExpressions; namespace Cryville.Crtr { public class ChartCompatibilityHandler : CustomCreationConverter { public static IMotionStringParser MotionStringParser { get; private set; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var obj = JToken.ReadFrom(reader); MotionStringParser = obj["format"].ToObject() switch { 2 => MotionStringParser2.Instance, 3 => MotionStringParser3.Instance, _ => throw new FormatException("Unsupported chart format"), }; return base.ReadJson(obj.CreateReader(), objectType, existingValue, serializer); } public override Chart Create(Type objectType) { return new Chart(); } public interface IMotionStringParser { void Parse(string str, out Identifier name, out MotionNode node); } class MotionStringParser2 : IMotionStringParser { static MotionStringParser2 _instance; public static MotionStringParser2 Instance { get { _instance ??= new MotionStringParser2(); return _instance; } } static readonly PdtFragmentInterpreter _itor = new(); static readonly PropOp _vecop = new VectorOp(v => _vecbuf = v); static float[] _vecbuf; public void Parse(string str, out Identifier name, out MotionNode node) { Match m = Regex.Match(str, @"^(.+?)(#(\d+))?(@(.+?))?(\^(.+?))?(\*(.+?))?(:(.+))?$"); if (!m.Success) throw new ArgumentException("Invalid motion string format"); name = new Identifier(m.Groups[1].Value); var registry = ChartPlayer.motionRegistry[name]; if (m.Groups[3].Success) { short id = short.Parse(m.Groups[3].Value); if (id < 0) throw new ArgumentException("Got negative motion node index"); Vec1 time = m.Groups[5].Success ? new Vec1(float.Parse(m.Groups[5].Value)) : null; /*byte? trs = m.Groups[7].Success ? byte.Parse(m.Groups[7].Value) : null; Vec1 rate = m.Groups[9].Success ? new Vec1(float.Parse(m.Groups[9].Value)) : null;*/ Vector value = m.Groups[11].Success ? Vector.Construct(registry.Type, ParseVector(m.Groups[11].Value)) : null; node = new MotionNode { Id = id, Time = time, Value = value }; } else { node = new MotionNode { Value = Vector.Construct(registry.Type, ParseVector(m.Groups[11].Value)) }; } } float[] ParseVector(string str) { var comps = str.Split(','); for (int i = 0; i < comps.Length; i++) { if (comps[i] == "") comps[i] = "0"; } _itor.SetSource(string.Format("({0});", string.Join(',', comps))); PdtEvaluator.Instance.Evaluate(_vecop, _itor.GetExp()); return _vecbuf; } } class MotionStringParser3 : IMotionStringParser { static MotionStringParser3 _instance; public static MotionStringParser3 Instance { get { _instance ??= new MotionStringParser3(); return _instance; } } static readonly PdtFragmentInterpreter _itor = new(); static readonly PropOp _vecop = new VectorOp(v => _vecbuf = v); static float[] _vecbuf; public void Parse(string str, out Identifier name, out MotionNode node) { Match m = Regex.Match(str, @"^([0-9A-Za-z_]+)(#(\d+))?(.+)?$"); if (!m.Success) throw new ArgumentException("Invalid motion string format"); name = new Identifier(m.Groups[1].Value); node = new MotionNode(); if (m.Groups[3].Success) { short id = short.Parse(m.Groups[3].Value); if (id < 0) throw new ArgumentException("Got negative motion node index"); node.Id = id; } if (m.Groups[4].Success) { _itor.SetSource(m.Groups[4].Value); while (_itor.Position < _itor.Source.Length) { var c = _itor.GetChar(); var exp = _itor.GetExp(); switch (c) { case '@': PdtEvaluator.Instance.Evaluate(_vecop, exp); node.Time = new Vec1(_vecbuf); break; case '~': PdtEvaluator.Instance.Evaluate(_vecop, exp); node.EndTime = new Vec1(_vecbuf); break; case '^': node.Transition = exp; break; case ':': PdtEvaluator.Instance.Evaluate(_vecop, exp); node.Value = Vector.Construct(ChartPlayer.motionRegistry[name].Type, _vecbuf); break; default: throw new ArgumentException("Invalid motion string format"); } } } else node.Reset = true; } } } }