using Cryville.Common.Pdt; using Cryville.Crtr.Event; using System.Collections.Generic; using UnityEngine; using UnityEngine.Profiling; namespace Cryville.Crtr { public class SkinContainer { readonly SkinElement _rootElement; readonly DynamicStack[] _stacks = new DynamicStack[2]; class DynamicStack { public readonly List Properties = new List(); public readonly List Elements = new List(); public void Clear() { Properties.Clear(); Elements.Clear(); } } struct DynamicProperty { public RuntimeSkinContext Context { get; set; } public SkinPropertyKey Key { get; set; } public PdtExpression Value { get; set; } } struct DynamicElement { public RuntimeSkinContext Context { get; set; } public SkinSelectors Selectors { get; set; } public SkinElement Element { get; set; } } public SkinContainer(SkinElement rootElement) { _rootElement = rootElement; for (int i = 0; i < _stacks.Length; i++) _stacks[i] = new DynamicStack(); } public void MatchStatic(ContainerState state) { var stack = _stacks[0]; stack.Clear(); ChartPlayer.etor.ContextState = state; ChartPlayer.etor.ContextEvent = state.Container; MatchStatic(_rootElement, state, stack, new RuntimeSkinContext(state.Handler.SkinContext)); ChartPlayer.etor.ContextEvent = null; ChartPlayer.etor.ContextState = null; } void MatchStatic(SkinElement rel, ContainerState state, DynamicStack stack, RuntimeSkinContext ctx) { var rc = ctx.ReadContext; ChartPlayer.etor.ContextTransform = rc.Transform; if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeInsert(rc.PropSrcs); foreach (var p in rel.properties) { p.Key.ExecuteStatic(state, ctx, p.Value); if (p.Key.IsValueRequired && !p.Value.IsConstant) stack.Properties.Add( new DynamicProperty { Context = ctx, Key = p.Key, Value = p.Value } ); } ChartPlayer.etor.ContextTransform = null; foreach (var e in rel.elements) { try { var nctxs = e.Key.MatchStatic(state, rc); if (nctxs != null) { var roflag = e.Key.annotations.Contains("if"); var woflag = e.Key.annotations.Contains("then"); foreach (var nctx in nctxs) { var nrctx = new RuntimeSkinContext(nctx, ctx, roflag, woflag); MatchStatic(e.Value, state, stack, nrctx); } } } catch (SelectorNotAvailableException) { stack.Elements.Add( new DynamicElement { Context = ctx, Selectors = e.Key, Element = e.Value } ); } } if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); } public void MatchDynamic(ContainerState state) { var stack = _stacks[state.CloneType >> 1]; var nstack = (state.CloneType >> 1) + 1 < _stacks.Length ? _stacks[(state.CloneType >> 1) + 1] : null; if (nstack != null) nstack.Clear(); if (stack.Properties.Count == 0 && stack.Elements.Count == 0) return; Profiler.BeginSample("SkinContainer.MatchDynamic"); ChartPlayer.etor.ContextState = state; ChartPlayer.etor.ContextEvent = state.Container; for (int i = 0; i < stack.Properties.Count; i++) { DynamicProperty p = stack.Properties[i]; p.Key.ExecuteDynamic(state, p.Context, p.Value); } for (int i = 0; i < stack.Elements.Count; i++) { DynamicElement e = stack.Elements[i]; var psrcs = e.Context.ReadContext.PropSrcs; if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs); SkinContext nctx = null; try { nctx = e.Selectors.MatchDynamic(state, e.Context.ReadContext); } catch (SelectorNotAvailableException) { if (nstack == null) throw; nstack.Elements.Add(e); } if (nctx != null) MatchDynamic(e.Element, state, nstack, new RuntimeSkinContext( nctx, e.Context, e.Selectors.annotations.Contains("if"), e.Selectors.annotations.Contains("then") )); if (psrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); } ChartPlayer.etor.ContextEvent = null; ChartPlayer.etor.ContextState = null; Profiler.EndSample(); } void MatchDynamic(SkinElement rel, ContainerState state, DynamicStack stack, RuntimeSkinContext ctx) { var rc = ctx.ReadContext; ChartPlayer.etor.ContextTransform = rc.Transform; if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeInsert(rc.PropSrcs); foreach (var p in rel.properties) { p.Key.ExecuteDynamic(state, ctx, p.Value); } ChartPlayer.etor.ContextTransform = null; foreach (var e in rel.elements) { if (e.Key.IsUpdatable(state)) { SkinContext nctx = e.Key.MatchDynamic(state, rc); if (nctx != null) MatchDynamic(e.Value, state, stack, new RuntimeSkinContext( nctx, ctx, e.Key.annotations.Contains("if"), e.Key.annotations.Contains("then") )); } else { if (stack == null) throw new SelectorNotAvailableException(); stack.Elements.Add( new DynamicElement { Context = ctx, Selectors = e.Key, Element = e.Value } ); } } if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); } } 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, RuntimeSkinContext oldctx, bool roflag, bool woflag) { if (roflag) { ReadContext = newctx; WriteTransform = oldctx.WriteTransform; } else if (woflag) { ReadContext = oldctx.ReadContext; WriteTransform = newctx.Transform; } else { ReadContext = newctx; WriteTransform = newctx.Transform; } } } }