From 43c87fba70c5842ff059cdc5818e48742ab6c91a Mon Sep 17 00:00:00 2001 From: PopSlime Date: Mon, 16 Jan 2023 15:08:25 +0800 Subject: [PATCH] Wrap Transform into SkinContext. Implement r/w context separation for skins. --- Assets/Cryville/Crtr/Anchor.cs | 11 ++- .../Cryville/Crtr/Event/ContainerHandler.cs | 8 +- Assets/Cryville/Crtr/SkinContainer.cs | 94 +++++++++++++------ Assets/Cryville/Crtr/SkinSelectors.cs | 58 ++++++------ 4 files changed, 105 insertions(+), 66 deletions(-) diff --git a/Assets/Cryville/Crtr/Anchor.cs b/Assets/Cryville/Crtr/Anchor.cs index 64a0b9f..6ea19e4 100644 --- a/Assets/Cryville/Crtr/Anchor.cs +++ b/Assets/Cryville/Crtr/Anchor.cs @@ -1,12 +1,17 @@ -using UnityEngine; +using System.Collections.Generic; +using UnityEngine; namespace Cryville.Crtr { public class Anchor { public int Name { get; private set; } - public Transform Transform { get; set; } - public Anchor(int name, Transform transform) { + public Transform Transform { get; private set; } + public SkinContext SkinContext { get; private set; } + public Dictionary PropSrcs { get; private set; } + public Anchor(int name, Transform transform, bool hasProps = false) { Name = name; Transform = transform; + if (hasProps) PropSrcs = new Dictionary(); + SkinContext = new SkinContext(transform, PropSrcs); } } } \ No newline at end of file diff --git a/Assets/Cryville/Crtr/Event/ContainerHandler.cs b/Assets/Cryville/Crtr/Event/ContainerHandler.cs index 33e13c0..c77c89e 100644 --- a/Assets/Cryville/Crtr/Event/ContainerHandler.cs +++ b/Assets/Cryville/Crtr/Event/ContainerHandler.cs @@ -36,7 +36,8 @@ namespace Cryville.Crtr.Event { /// /// group, the containing all the generated elements in the . /// - public Transform gogroup; + protected Transform gogroup; + public SkinContext SkinContext; public Vector3 Position { get; protected set; } public Quaternion Rotation { get; protected set; } @@ -69,16 +70,17 @@ namespace Cryville.Crtr.Event { protected readonly static int _a_tail = IdentifierManager.SharedInstance.Request("tail"); public virtual void PreInit() { gogroup = new GameObject(TypeName + ":" + Container.GetHashCode().ToString(CultureInfo.InvariantCulture)).transform; + SkinContext = new SkinContext(gogroup); if (cs.Parent != null) gogroup.SetParent(cs.Parent.Handler.gogroup, false); a_cur = RegisterAnchor(_a_cur); a_head = RegisterAnchor(_a_head); a_tail = RegisterAnchor(_a_tail); } - protected Anchor RegisterAnchor(int name) { + protected Anchor RegisterAnchor(int name, bool hasPropSrcs = false) { var go = new GameObject("." + IdentifierManager.SharedInstance.Retrieve(name)).transform; go.SetParent(gogroup, false); - var result = new Anchor(name, go); + var result = new Anchor(name, go, hasPropSrcs); List list; if (!Anchors.TryGetValue(name, out list)) Anchors.Add(name, list = new List()); diff --git a/Assets/Cryville/Crtr/SkinContainer.cs b/Assets/Cryville/Crtr/SkinContainer.cs index 9f84e53..9a88209 100644 --- a/Assets/Cryville/Crtr/SkinContainer.cs +++ b/Assets/Cryville/Crtr/SkinContainer.cs @@ -12,90 +12,98 @@ namespace Cryville.Crtr { readonly PdtSkin skin; readonly List dynprops = new List(); struct DynamicProperty { - public Transform Anchor { get; set; } + public RuntimeSkinContext Context { get; set; } public SkinPropertyKey Key { get; set; } public PdtExpression Value { get; set; } } readonly List dynelems = new List(); struct DynamicElement { - public Transform Anchor { get; set; } + public RuntimeSkinContext Context { get; set; } public SkinSelectors Selectors { get; set; } public SkinElement Element { get; set; } } public SkinContainer(PdtSkin _skin) { skin = _skin; } - public void MatchStatic(ContainerState context) { + public void MatchStatic(ContainerState state) { dynprops.Clear(); dynelems.Clear(); - ChartPlayer.etor.ContextState = context; - ChartPlayer.etor.ContextEvent = context.Container; - MatchStatic(skin, context, context.Handler.gogroup); + ChartPlayer.etor.ContextState = state; + ChartPlayer.etor.ContextEvent = state.Container; + MatchStatic(skin, state, new RuntimeSkinContext(state.Handler.SkinContext)); ChartPlayer.etor.ContextEvent = null; ChartPlayer.etor.ContextState = null; } - void MatchStatic(SkinElement rel, ContainerState context, Transform anchor = null) { - ChartPlayer.etor.ContextTransform = anchor; + void MatchStatic(SkinElement rel, ContainerState state, RuntimeSkinContext ctx) { + var rc = ctx.ReadContext; + ChartPlayer.etor.ContextTransform = rc.Transform; foreach (var p in rel.properties) { if (p.Key.Name == 0) - anchor.gameObject.AddComponent(p.Key.Component); + rc.Transform.gameObject.AddComponent(p.Key.Component); else { - ChartPlayer.etor.Evaluate(GetPropOp(anchor, p.Key).Operator, p.Value); + ChartPlayer.etor.Evaluate(GetPropOp(ctx.WriteTransform, p.Key).Operator, p.Value); if (!p.Value.IsConstant) dynprops.Add( - new DynamicProperty { Anchor = anchor, Key = p.Key, Value = p.Value } + new DynamicProperty { Context = ctx, Key = p.Key, Value = p.Value } ); } } ChartPlayer.etor.ContextTransform = null; foreach (var r in rel.elements) { try { - var new_anchors = r.Key.MatchStatic(context, anchor); - if (new_anchors != null) foreach (var new_anchor in new_anchors) { - MatchStatic(r.Value, context, new_anchor); + var nctxs = r.Key.MatchStatic(state, rc); + var roflag = r.Key.annotations.Contains("if"); + foreach (var nctx in nctxs) { + var nrctx = new RuntimeSkinContext(nctx, ctx.WriteTransform, roflag); + MatchStatic(r.Value, state, nrctx); } } catch (SelectorNotStaticException) { dynelems.Add( - new DynamicElement { Anchor = anchor, Selectors = r.Key, Element = r.Value } + new DynamicElement { Context = ctx, Selectors = r.Key, Element = r.Value } ); } } } - public void MatchDynamic(ContainerState context) { + public void MatchDynamic(ContainerState state) { if (dynprops.Count == 0 && dynelems.Count == 0) return; Profiler.BeginSample("SkinContainer.MatchDynamic"); - ChartPlayer.etor.ContextState = context; - ChartPlayer.etor.ContextEvent = context.Container; + ChartPlayer.etor.ContextState = state; + ChartPlayer.etor.ContextEvent = state.Container; for (int i = 0; i < dynprops.Count; i++) { DynamicProperty p = dynprops[i]; - var prop = GetPropOp(p.Anchor, p.Key); - if (context.CloneType > prop.UpdateCloneType) continue; + var prop = GetPropOp(p.Context.WriteTransform, p.Key); + if (state.CloneType > prop.UpdateCloneType) continue; ChartPlayer.etor.Evaluate(prop.Operator, p.Value); } for (int i = 0; i < dynelems.Count; i++) { DynamicElement e = dynelems[i]; - var anchor = e.Selectors.MatchDynamic(context, e.Anchor); - if (anchor != null) MatchDynamic(e.Element, context, anchor); + var nctx = e.Selectors.MatchDynamic(state, e.Context.ReadContext); + if (nctx != null) MatchDynamic( + e.Element, state, + new RuntimeSkinContext(nctx, e.Context.ReadContext.Transform, e.Selectors.annotations.Contains("if")) + ); } ChartPlayer.etor.ContextEvent = null; ChartPlayer.etor.ContextState = null; Profiler.EndSample(); } - void MatchDynamic(SkinElement rel, ContainerState context, Transform anchor = null) { - ChartPlayer.etor.ContextTransform = anchor; + void MatchDynamic(SkinElement rel, ContainerState state, RuntimeSkinContext ctx) { + var rc = ctx.ReadContext; + ChartPlayer.etor.ContextTransform = rc.Transform; 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(anchor, p.Key); - if (context.CloneType > prop.UpdateCloneType) continue; + var prop = GetPropOp(ctx.WriteTransform, p.Key); + if (state.CloneType > prop.UpdateCloneType) continue; ChartPlayer.etor.Evaluate(prop.Operator, p.Value); } ChartPlayer.etor.ContextTransform = null; foreach (var r in rel.elements) { - if (!r.Key.IsUpdatable(context)) continue; - var new_anchor = r.Key.MatchDynamic(context, anchor); - if (new_anchor != null) { - MatchDynamic(r.Value, context, new_anchor); - } + if (!r.Key.IsUpdatable(state)) continue; + var nctx = r.Key.MatchDynamic(state, rc); + if (nctx != null) MatchDynamic( + r.Value, state, + new RuntimeSkinContext(nctx, ctx.WriteTransform, r.Key.annotations.Contains("if")) + ); } } SkinProperty GetPropOp(Transform obj, SkinPropertyKey key) { @@ -114,4 +122,28 @@ namespace Cryville.Crtr { return result; } } + public class SkinContext { + public Transform Transform { get; private set; } + public Dictionary PropSrcs { get; private set; } + public SkinContext(Transform transform, Dictionary propSrcs = null) { + Transform = transform; + PropSrcs = propSrcs; + } + } + public struct RuntimeSkinContext { + public SkinContext ReadContext { get; private set; } + public Transform WriteTransform { get; private set; } + public RuntimeSkinContext(SkinContext rw) { + ReadContext = rw; + WriteTransform = rw.Transform; + } + public RuntimeSkinContext(SkinContext r, Transform w) { + ReadContext = r; + WriteTransform = w; + } + public RuntimeSkinContext(SkinContext newctx, Transform oldctx, bool roflag) { + ReadContext = newctx; + WriteTransform = roflag ? oldctx : newctx.Transform; + } + } } diff --git a/Assets/Cryville/Crtr/SkinSelectors.cs b/Assets/Cryville/Crtr/SkinSelectors.cs index b3b8609..dceef81 100644 --- a/Assets/Cryville/Crtr/SkinSelectors.cs +++ b/Assets/Cryville/Crtr/SkinSelectors.cs @@ -12,11 +12,11 @@ using CAnchor = Cryville.Crtr.Anchor; namespace Cryville.Crtr { public class SkinSelectors { readonly SkinSelector[] selectors; - readonly string[] annotations; + public readonly HashSet annotations; public SkinSelectors(IEnumerable s, IEnumerable a) { selectors = s.ToArray(); - annotations = a.ToArray(); + annotations = a.ToHashSet(); } public override string ToString() { if (selectors.Length == 0) return ""; @@ -37,8 +37,8 @@ namespace Cryville.Crtr { selectors[i].Optimize(etor); } } - public IEnumerable MatchStatic(ContainerState h, Transform anchor) { - IEnumerable result = new Transform[] { anchor }; + public IEnumerable MatchStatic(ContainerState h, SkinContext ctx) { + IEnumerable result = new SkinContext[] { ctx }; foreach (var s in selectors) { result = result.SelectMany(l => s.MatchStatic(h, l)); } @@ -49,30 +49,30 @@ namespace Cryville.Crtr { if (!s.IsUpdatable(h)) return false; return true; } - public Transform MatchDynamic(ContainerState h, Transform anchor) { + public SkinContext MatchDynamic(ContainerState h, SkinContext ctx) { foreach (var s in selectors) { - anchor = s.MatchDynamic(h, anchor); - if (anchor == null) return null; + ctx = s.MatchDynamic(h, ctx); + if (ctx == null) return null; } - return anchor; + return ctx; } } public abstract class SkinSelector { protected SkinSelector() { } public virtual void Optimize(PdtEvaluatorBase etor) { } - public virtual IEnumerable MatchStatic(ContainerState h, Transform a) { throw new SelectorNotStaticException(); } - public virtual Transform MatchDynamic(ContainerState h, Transform a) { throw new NotSupportedException(); } + public virtual IEnumerable MatchStatic(ContainerState h, SkinContext c) { throw new SelectorNotStaticException(); } + public virtual SkinContext MatchDynamic(ContainerState h, SkinContext c) { throw new NotSupportedException(); } public virtual bool IsUpdatable(ContainerState h) { return true; } public class CreateObject : SkinSelector { public CreateObject() { } - public override IEnumerable MatchStatic(ContainerState h, Transform a) { + public override IEnumerable MatchStatic(ContainerState h, SkinContext c) { var obj = new GameObject("__obj__"); - obj.transform.SetParent(a, false); + obj.transform.SetParent(c.Transform, false); obj.AddComponent(); - return new Transform[] { obj.transform }; + return new SkinContext[] { new SkinContext(obj.transform) }; } } public class Anchor : SkinSelector { @@ -81,12 +81,12 @@ namespace Cryville.Crtr { Name = IdentifierManager.SharedInstance.Request(name); } - public override IEnumerable MatchStatic(ContainerState h, Transform a) { + public override IEnumerable MatchStatic(ContainerState h, SkinContext c) { List anchors; if (h.Handler.Anchors.TryGetValue(Name, out anchors)) { - return anchors.Select(a => a.Transform); + return anchors.Select(a => a.SkinContext); } - else return Enumerable.Empty(); + else return Enumerable.Empty(); } public override bool IsUpdatable(ContainerState h) { return h.Handler.OpenedAnchor.Name == Name; @@ -97,8 +97,8 @@ namespace Cryville.Crtr { public AtAnchor(string name) { Name = IdentifierManager.SharedInstance.Request(name); } - public override Transform MatchDynamic(ContainerState h, Transform a) { - return IsUpdatable(h) ? a : null; + public override SkinContext MatchDynamic(ContainerState h, SkinContext c) { + return IsUpdatable(h) ? c : null; } public override bool IsUpdatable(ContainerState h) { return h.Handler.OpenedAnchor.Name == Name; @@ -115,16 +115,16 @@ namespace Cryville.Crtr { public override void Optimize(PdtEvaluatorBase etor) { etor.Optimize(_exp); } - public override IEnumerable MatchStatic(ContainerState h, Transform a) { - var result = Match(a); - if (result != null) return new Transform[] { result }; - else return Enumerable.Empty(); + public override IEnumerable MatchStatic(ContainerState h, SkinContext c) { + var result = Match(c); + if (result != null) return new SkinContext[] { result }; + else return Enumerable.Empty(); } - public override Transform MatchDynamic(ContainerState h, Transform a) { - return Match(a, true); + public override SkinContext MatchDynamic(ContainerState h, SkinContext c) { + return Match(c, true); } - public Transform Match(Transform a, bool dyn = false) { - ChartPlayer.etor.ContextTransform = a; + public SkinContext Match(SkinContext a, bool dyn = false) { + ChartPlayer.etor.ContextTransform = a.Transform; try { ChartPlayer.etor.Evaluate(_op, _exp); return _flag ? a : null; @@ -140,15 +140,15 @@ namespace Cryville.Crtr { } public class State : SkinSelector { public State(string state) { } - public override Transform MatchDynamic(ContainerState h, Transform a) { + public override SkinContext MatchDynamic(ContainerState h, SkinContext c) { return null; } } public class ElementType : SkinSelector { readonly string _type; public ElementType(string type) { _type = type; } - public override IEnumerable MatchStatic(ContainerState h, Transform a) { - return h.Handler.TypeName == _type ? new Transform[] { a } : Enumerable.Empty(); + public override IEnumerable MatchStatic(ContainerState h, SkinContext c) { + return h.Handler.TypeName == _type ? new SkinContext[] { c } : Enumerable.Empty(); } } }