diff --git a/Assets/Cryville/Crtr/Skin.cs b/Assets/Cryville/Crtr/Skin.cs index c838c56..a57414d 100644 --- a/Assets/Cryville/Crtr/Skin.cs +++ b/Assets/Cryville/Crtr/Skin.cs @@ -1,13 +1,8 @@ -using Cryville.Common; using Cryville.Common.Pdt; using Cryville.Crtr.Browsing; -using Cryville.Crtr.Components; using Newtonsoft.Json; -using System; using System.Collections.Generic; -using System.Globalization; using System.IO; -using System.Reflection; using System.Text; namespace Cryville.Crtr { @@ -37,7 +32,6 @@ namespace Cryville.Crtr { public class PdtSkin : SkinElement { } - [Binder(typeof(SkinElementBinder))] public class SkinElement { [ElementList] public Dictionary elements @@ -67,36 +61,4 @@ namespace Cryville.Crtr { } } } - public struct SkinPropertyKey { - public Type Component; - public int Name; - } - public class SkinElementBinder : EmptyBinder { - public override object ChangeType(object value, Type type, CultureInfo culture) { - if (value is string && type == typeof(SkinPropertyKey)) { - var cp = ((string)value).Split('.'); - switch (cp.Length) { - case 1: - var key = cp[0]; - if (key[0] == '*') - return new SkinPropertyKey { Component = GetComponentByName(key.Substring(1)) }; - else - return new SkinPropertyKey { Component = typeof(TransformInterface), Name = IdentifierManager.SharedInstance.Request(key) }; - case 2: - return new SkinPropertyKey { Component = GetComponentByName(cp[0]), Name = IdentifierManager.SharedInstance.Request(cp[1]) }; - } - } - return base.ChangeType(value, type, culture); - } - - static readonly char[] nssep = new char[]{':'}; - Type GetComponentByName(string name) { - var nstuple = name.Split(nssep, 2); - var ns = nssep.Length == 2 ? nstuple[0] : "generic"; - name = nssep.Length == 2 ? nstuple[1] : nstuple[0]; - if (ns == "generic") - return GenericResources.Components[name]; - throw new ArgumentException(string.Format("Component type {0} not found", name)); - } - } } diff --git a/Assets/Cryville/Crtr/SkinContainer.cs b/Assets/Cryville/Crtr/SkinContainer.cs index 338fcd5..063725e 100644 --- a/Assets/Cryville/Crtr/SkinContainer.cs +++ b/Assets/Cryville/Crtr/SkinContainer.cs @@ -1,8 +1,5 @@ -using Cryville.Common; using Cryville.Common.Pdt; -using Cryville.Crtr.Components; using Cryville.Crtr.Event; -using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Profiling; @@ -38,14 +35,10 @@ namespace Cryville.Crtr { ChartPlayer.etor.ContextTransform = rc.Transform; if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeInsert(rc.PropSrcs); foreach (var p in rel.properties) { - if (p.Key.Name == 0) - rc.Transform.gameObject.AddComponent(p.Key.Component); - else { - ChartPlayer.etor.Evaluate(GetPropOp(ctx.WriteTransform, p.Key).Operator, p.Value); - if (!p.Value.IsConstant) dynprops.Add( - new DynamicProperty { Context = ctx, Key = p.Key, Value = p.Value } - ); - } + p.Key.ExecuteStatic(state, ctx, p.Value); + if (p.Key.IsValueRequired && !p.Value.IsConstant) dynprops.Add( + new DynamicProperty { Context = ctx, Key = p.Key, Value = p.Value } + ); } ChartPlayer.etor.ContextTransform = null; foreach (var r in rel.elements) { @@ -73,12 +66,7 @@ namespace Cryville.Crtr { ChartPlayer.etor.ContextEvent = state.Container; for (int i = 0; i < dynprops.Count; i++) { DynamicProperty p = dynprops[i]; - var psrcs = p.Context.ReadContext.PropSrcs; - if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs); - var prop = GetPropOp(p.Context.WriteTransform, p.Key); - if (state.CloneType > prop.UpdateCloneType) continue; - ChartPlayer.etor.Evaluate(prop.Operator, p.Value); - if (psrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); + p.Key.ExecuteDynamic(state, p.Context, p.Value); } for (int i = 0; i < dynelems.Count; i++) { DynamicElement e = dynelems[i]; @@ -99,11 +87,7 @@ namespace Cryville.Crtr { ChartPlayer.etor.ContextTransform = rc.Transform; if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeInsert(rc.PropSrcs); foreach (var p in rel.properties) { - if (p.Key.Name == 0) - throw new InvalidOperationException("Component creation in dynamic context is not allowed"); - var prop = GetPropOp(ctx.WriteTransform, p.Key); - if (state.CloneType > prop.UpdateCloneType) continue; - ChartPlayer.etor.Evaluate(prop.Operator, p.Value); + p.Key.ExecuteDynamic(state, ctx, p.Value); } ChartPlayer.etor.ContextTransform = null; foreach (var r in rel.elements) { @@ -115,21 +99,6 @@ namespace Cryville.Crtr { } if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); } - SkinProperty GetPropOp(Transform obj, SkinPropertyKey key) { - var ctype = key.Component; - var comp = (SkinComponent)obj.GetComponent(ctype); - if (comp == null) throw new InvalidOperationException(string.Format( - "Trying to set property {0} but the component is not found", - IdentifierManager.SharedInstance.Retrieve(key.Name) - )); - SkinProperty result; - if (!comp.Properties.TryGetValue(key.Name, out result)) - throw new ArgumentException(string.Format( - "Property {0} not found on component", - IdentifierManager.SharedInstance.Retrieve(key.Name) - )); - return result; - } } public class SkinContext { public Transform Transform { get; private set; } diff --git a/Assets/Cryville/Crtr/SkinInterpreter.cs b/Assets/Cryville/Crtr/SkinInterpreter.cs index 03c86cd..2b8da48 100644 --- a/Assets/Cryville/Crtr/SkinInterpreter.cs +++ b/Assets/Cryville/Crtr/SkinInterpreter.cs @@ -1,4 +1,6 @@ -using Cryville.Common.Pdt; +using Cryville.Common; +using Cryville.Common.Pdt; +using Cryville.Crtr.Components; using System; using System.Collections.Generic; using System.Reflection; @@ -8,10 +10,11 @@ namespace Cryville.Crtr { public SkinInterpreter(string src, Binder binder) : base(src, typeof(PdtSkin), binder) { } readonly List s = new List(); - readonly List a = new List(); + readonly HashSet a = new HashSet(); + readonly List k = new List(2); protected override object InterpretKey(Type type) { - s.Clear(); a.Clear(); - string key = ""; + s.Clear(); a.Clear(); k.Clear(); + bool invalidKeyFlag = false, compKeyFlag = false; while (true) { int pp = Position; switch (cc) { @@ -22,19 +25,22 @@ namespace Cryville.Crtr { case '$': GetChar(); s.Add(new SkinSelector.CreateObject()); - key = null; + invalidKeyFlag = true; break; case '.': GetChar(); if (cc == '.') { GetChar(); s.Add(new SkinSelector.AtAnchor(GetIdentifier())); - key = null; + invalidKeyFlag = true; } else { var p3 = GetIdentifier(); s.Add(new SkinSelector.Anchor(p3)); - if (key != null) key += "." + p3; + if (!invalidKeyFlag) { + if (k.Count != 1) invalidKeyFlag = true; + else k.Add(p3); + } } break; case '>': @@ -43,24 +49,61 @@ namespace Cryville.Crtr { break; case ';': case ':': - return key; + if (invalidKeyFlag) throw new FormatException("Invalid key format"); + if (a.Contains("has")) { + if (k.Count != 1) throw new FormatException("Invalid anchor name"); + return new SkinPropertyKey.CreateAnchor { + Name = IdentifierManager.SharedInstance.Request(k[0]) + }; + } + else if (a.Contains("at")) { + if (k.Count != 1) throw new FormatException("Invalid anchor name"); + return new SkinPropertyKey.SetAnchor { + Name = IdentifierManager.SharedInstance.Request(k[0]) + }; + } + switch (k.Count) { + case 1: + if (compKeyFlag) return new SkinPropertyKey.CreateComponent { + Component = GetComponentByName(k[0]) + }; + else return new SkinPropertyKey.SetProperty { + Component = typeof(TransformInterface), + Name = IdentifierManager.SharedInstance.Request(k[0]) + }; + case 2: + return new SkinPropertyKey.SetProperty { + Component = GetComponentByName(k[0]), + Name = IdentifierManager.SharedInstance.Request(k[1]) + }; + default: + throw new FormatException("Unknown error"); // Unreachable + } case '{': return new SkinSelectors(s, a); case '}': return null; case '*': GetChar(); - key += "*"; + compKeyFlag = true; break; default: var p4 = GetIdentifier(); s.Add(new SkinSelector.ElementType(p4)); - if (key != null) key += p4; + if (!invalidKeyFlag) { + if (k.Count != 0) invalidKeyFlag = true; + else k.Add(p4); + } break; } ws(); if (Position == pp) throw new FormatException("Invalid selector or key format"); } } + static Type GetComponentByName(string name) { + Type result; + if (GenericResources.Components.TryGetValue(name, out result)) return result; + throw new ArgumentException(string.Format("Component type {0} not found", name)); + } } } diff --git a/Assets/Cryville/Crtr/SkinPropertyKey.cs b/Assets/Cryville/Crtr/SkinPropertyKey.cs new file mode 100644 index 0000000..2188068 --- /dev/null +++ b/Assets/Cryville/Crtr/SkinPropertyKey.cs @@ -0,0 +1,91 @@ +using Cryville.Common; +using Cryville.Common.Pdt; +using Cryville.Crtr.Components; +using Cryville.Crtr.Event; +using System; +using UnityEngine; + +namespace Cryville.Crtr { + public abstract class SkinPropertyKey { + public abstract override string ToString(); + public abstract bool IsValueRequired { get; } + public abstract void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp); + public abstract void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp); + public class CreateComponent : SkinPropertyKey { + public Type Component { get; set; } + public override string ToString() { + return string.Format("*{0}", Component.Name); + } + public override bool IsValueRequired { get { return false; } } + public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + ctx.ReadContext.Transform.gameObject.AddComponent(Component); + } + public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + throw new InvalidOperationException("Component creation in dynamic context is not allowed"); + } + } + public class SetProperty : SkinPropertyKey { + public Type Component { get; set; } + public int Name { get; set; } + public override string ToString() { + return string.Format("{0}.{1}", Component.Name, IdentifierManager.SharedInstance.Retrieve(Name)); + } + public override bool IsValueRequired { get { return true; } } + public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + Execute(ctx, GetPropOp(ctx.WriteTransform).Operator, exp); + } + public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + var prop = GetPropOp(ctx.WriteTransform); + if (state.CloneType > prop.UpdateCloneType) return; + Execute(ctx, prop.Operator, exp); + } + void Execute(RuntimeSkinContext ctx, PdtOperator op, PdtExpression exp) { + var psrcs = ctx.ReadContext.PropSrcs; + if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs); + ChartPlayer.etor.Evaluate(op, exp); + if (psrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); + } + SkinProperty GetPropOp(Transform obj) { + var ctype = Component; + var comp = (SkinComponent)obj.GetComponent(ctype); + if (comp == null) throw new InvalidOperationException(string.Format( + "Trying to set property {0} but the component is not found", + IdentifierManager.SharedInstance.Retrieve(Name) + )); + SkinProperty result; + if (!comp.Properties.TryGetValue(Name, out result)) + throw new InvalidOperationException(string.Format( + "Property {0} not found on component", + IdentifierManager.SharedInstance.Retrieve(Name) + )); + return result; + } + } + public class CreateAnchor : SkinPropertyKey { + public int Name { get; set; } + public override string ToString() { + return string.Format("@has {0}", IdentifierManager.SharedInstance.Retrieve(Name)); + } + public override bool IsValueRequired { get { return false; } } + public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + // TODO + } + public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + throw new InvalidOperationException("Anchor creation in dynamic context is not allowed"); + } + } + public class SetAnchor : SkinPropertyKey { + public int Name { get; set; } + public override string ToString() { + return string.Format("@at {0}", IdentifierManager.SharedInstance.Retrieve(Name)); + } + public override bool IsValueRequired { get { return true; } } + public override void ExecuteStatic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + // TODO + } + public override void ExecuteDynamic(ContainerState state, RuntimeSkinContext ctx, PdtExpression exp) { + // TODO + } + } + } +} diff --git a/Assets/Cryville/Crtr/SkinPropertyKey.cs.meta b/Assets/Cryville/Crtr/SkinPropertyKey.cs.meta new file mode 100644 index 0000000..ee1e836 --- /dev/null +++ b/Assets/Cryville/Crtr/SkinPropertyKey.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 701f7f917dc59c540b105732747aeb67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: