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; namespace Cryville.Crtr { public class SkinContainer { readonly PdtSkin skin; readonly List dynprops = new List(); struct DynamicProperty { public RuntimeSkinContext Context { get; set; } public SkinPropertyKey Key { get; set; } public PdtExpression Value { get; set; } } readonly List dynelems = new List(); struct DynamicElement { 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 state) { dynprops.Clear(); dynelems.Clear(); 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 state, 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) { 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 } ); } } ChartPlayer.etor.ContextTransform = null; foreach (var r in rel.elements) { try { var nctxs = r.Key.MatchStatic(state, rc); var roflag = r.Key.annotations.Contains("if"); var woflag = r.Key.annotations.Contains("then"); foreach (var nctx in nctxs) { var nrctx = new RuntimeSkinContext(nctx, ctx, roflag, woflag); MatchStatic(r.Value, state, nrctx); } } catch (SelectorNotAvailableException) { dynelems.Add( new DynamicElement { Context = ctx, Selectors = r.Key, Element = r.Value } ); } } if (rc.PropSrcs != null) ChartPlayer.etor.ContextCascadeDiscard(); } public void MatchDynamic(ContainerState state) { if (dynprops.Count == 0 && dynelems.Count == 0) return; Profiler.BeginSample("SkinContainer.MatchDynamic"); ChartPlayer.etor.ContextState = state; 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(); } for (int i = 0; i < dynelems.Count; i++) { DynamicElement e = dynelems[i]; var psrcs = e.Context.ReadContext.PropSrcs; if (psrcs != null) ChartPlayer.etor.ContextCascadeInsert(psrcs); var nctx = e.Selectors.MatchDynamic(state, e.Context.ReadContext); if (nctx != null) MatchDynamic(e.Element, state, 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, 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) { 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); } ChartPlayer.etor.ContextTransform = null; foreach (var r in rel.elements) { if (!r.Key.IsUpdatable(state)) continue; var nctx = r.Key.MatchDynamic(state, rc); if (nctx != null) MatchDynamic(r.Value, state, new RuntimeSkinContext( nctx, ctx, r.Key.annotations.Contains("if"), r.Key.annotations.Contains("then") )); } 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; } 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; } } } }