diff --git a/Assets/Cryville/Crtr/Chart.cs b/Assets/Cryville/Crtr/Chart.cs index 20c6345..614752b 100644 --- a/Assets/Cryville/Crtr/Chart.cs +++ b/Assets/Cryville/Crtr/Chart.cs @@ -242,6 +242,7 @@ namespace Cryville.Crtr { } } + [JsonConverter(typeof(ChartCompatibilityHandler))] public class Chart : EventContainer { [JsonRequired] public long format; // Format Version @@ -308,40 +309,7 @@ namespace Cryville.Crtr { private void LoadFromString(string s) { if (Node != null) throw new InvalidOperationException("The motion property can only be set at initialization"); - Match m = Regex.Match(s, @"^([0-9A-Za-z_]+)(#(\d+))?(.+)?$"); - if (!m.Success) throw new ArgumentException("Invalid motion string format"); - name = new Identifier(m.Groups[1].Value); - var registry = ChartPlayer.motionRegistry[name]; - 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 '@': - ChartPlayer.etor.Evaluate(_vecop, exp); - Node.Time = new Vec1(_vecbuf); - break; - case '~': - ChartPlayer.etor.Evaluate(_vecop, exp); - Node.EndTime = new Vec1(_vecbuf); - break; - case ':': - ChartPlayer.etor.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; + ChartCompatibilityHandler.MotionStringParser.Parse(s, out name, out Node); SubmitPropSrc("value", new VectorSrc(() => Node.Value)); } diff --git a/Assets/Cryville/Crtr/ChartCompatibilityHandler.cs b/Assets/Cryville/Crtr/ChartCompatibilityHandler.cs new file mode 100644 index 0000000..2773653 --- /dev/null +++ b/Assets/Cryville/Crtr/ChartCompatibilityHandler.cs @@ -0,0 +1,122 @@ +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); + switch (obj["format"].ToObject()) { + case 2: MotionStringParser = MotionStringParser2.Instance; break; + case 3: MotionStringParser = MotionStringParser3.Instance; break; + default: 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 { + if (_instance == null) + _instance = new MotionStringParser2(); + return _instance; + } + } + static readonly PdtFragmentInterpreter _itor = new PdtFragmentInterpreter(); + 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))); + ChartPlayer.etor.Evaluate(_vecop, _itor.GetExp()); + return _vecbuf; + } + } + class MotionStringParser3 : IMotionStringParser { + static MotionStringParser3 _instance; + public static MotionStringParser3 Instance { + get { + if (_instance == null) + _instance = new MotionStringParser3(); + return _instance; + } + } + static readonly PdtFragmentInterpreter _itor = new PdtFragmentInterpreter(); + 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 '@': + ChartPlayer.etor.Evaluate(_vecop, exp); + node.Time = new Vec1(_vecbuf); + break; + case '~': + ChartPlayer.etor.Evaluate(_vecop, exp); + node.EndTime = new Vec1(_vecbuf); + break; + case ':': + ChartPlayer.etor.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; + } + } + } +} diff --git a/Assets/Cryville/Crtr/ChartCompatibilityHandler.cs.meta b/Assets/Cryville/Crtr/ChartCompatibilityHandler.cs.meta new file mode 100644 index 0000000..9ec7ed7 --- /dev/null +++ b/Assets/Cryville/Crtr/ChartCompatibilityHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4c3afb80951eef4caf51bf11e473605 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Crtr/ChartPlayer.cs b/Assets/Cryville/Crtr/ChartPlayer.cs index ae74e5c..a2b1a42 100644 --- a/Assets/Cryville/Crtr/ChartPlayer.cs +++ b/Assets/Cryville/Crtr/ChartPlayer.cs @@ -608,7 +608,6 @@ namespace Cryville.Crtr { MissingMemberHandling = MissingMemberHandling.Error }); - if (chart.format != 3) throw new FormatException("Invalid chart file format version"); Logger.Log("main", 0, "Load/WorkerThread", "Applying ruleset (iteration 1)"); loadPregress = .10f; pruleset.PrePatch(chart);