201 lines
9.4 KiB
C#
201 lines
9.4 KiB
C#
using Cryville.Common;
|
|
using Cryville.Common.Collections.Specialized;
|
|
using Cryville.Common.Pdt;
|
|
using Cryville.Crtr.Skin.Components;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace Cryville.Crtr.Skin {
|
|
public abstract class SkinPropertyKey {
|
|
public static SkinPropertyKey Construct(HashSet<string> a, IReadOnlyList<string> k, bool compKeyFlag) {
|
|
if (a.Remove("has")) {
|
|
if (k.Count != 1) throw new FormatException("Invalid anchor name");
|
|
return new CreateAnchor(a, IdentifierManager.Shared.Request(k[0]));
|
|
}
|
|
else if (a.Remove("at")) {
|
|
if (k.Count != 1) throw new FormatException("Invalid anchor name");
|
|
return new SetAnchor(a, IdentifierManager.Shared.Request(k[0]));
|
|
}
|
|
else if (a.Remove("emit")) {
|
|
if (k.Count != 1) throw new FormatException("Invalid effect name");
|
|
return new EmitEffect(a, IdentifierManager.Shared.Request(k[0]));
|
|
}
|
|
else if (a.Remove("emit_self")) {
|
|
if (k.Count != 1) throw new FormatException("Invalid effect name");
|
|
return new EmitEffect(a, IdentifierManager.Shared.Request(k[0]), true);
|
|
}
|
|
else if (a.Remove("var")) {
|
|
if (k.Count != 1) throw new FormatException("Invalid variable name");
|
|
return new SetVariable(a, IdentifierManager.Shared.Request(k[0]));
|
|
}
|
|
switch (k.Count) {
|
|
case 1:
|
|
if (compKeyFlag) return new CreateComponent(a, GetComponentByName(k[0]));
|
|
else return new SetProperty(a, typeof(TransformInterface), IdentifierManager.Shared.Request(k[0]));
|
|
case 2:
|
|
return new SetProperty(a, GetComponentByName(k[0]), IdentifierManager.Shared.Request(k[1]));
|
|
default:
|
|
throw new FormatException("Unknown error");
|
|
}
|
|
static Type GetComponentByName(string name) {
|
|
if (BuiltinResources.Components.TryGetValue(name, out Type result)) return result;
|
|
throw new ArgumentException(string.Format("Component type \"{0}\" not found", name));
|
|
}
|
|
}
|
|
public readonly HashSet<string> annotations;
|
|
public SkinPropertyKey(IEnumerable<string> a) {
|
|
annotations = a.ToHashSet();
|
|
}
|
|
public abstract override string ToString();
|
|
public abstract bool IsValueRequired { get; }
|
|
public abstract void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars);
|
|
public abstract void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl);
|
|
public class CreateComponent : SkinPropertyKey {
|
|
public Type Component { get; private set; }
|
|
public CreateComponent(IEnumerable<string> a, Type component) : base(a) {
|
|
Component = component;
|
|
}
|
|
public override string ToString() {
|
|
return string.Format("*{0}", Component.Name);
|
|
}
|
|
public override bool IsValueRequired { get { return false; } }
|
|
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
|
ctx.WriteTransform.gameObject.AddComponent(Component);
|
|
}
|
|
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
|
throw new InvalidOperationException("Component creation in dynamic context is not allowed");
|
|
}
|
|
}
|
|
public class SetProperty : SkinPropertyKey {
|
|
public Type Component { get; private set; }
|
|
public int Name { get; private set; }
|
|
public SetProperty(IEnumerable<string> a, Type component, int name) : base(a) {
|
|
Component = component;
|
|
Name = name;
|
|
}
|
|
public override string ToString() {
|
|
return string.Format("{0}.{1}", Component.Name, IdentifierManager.Shared.Retrieve(Name));
|
|
}
|
|
public override bool IsValueRequired { get { return true; } }
|
|
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
|
Execute(ctx, GetPropOp(ctx.WriteTransform).Operator, exp);
|
|
}
|
|
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
|
var prop = GetPropOp(ctx.WriteTransform);
|
|
if (dl > prop.UpdateDynamicLevel) return;
|
|
Execute(ctx, prop.Operator, exp);
|
|
}
|
|
void Execute(RuntimeSkinContext ctx, PdtOperator op, PdtExpression exp) {
|
|
var psrcs = ctx.ReadContext.PropSrcs;
|
|
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(psrcs);
|
|
if (!PdtEvaluator.Instance.Evaluate(op, exp))
|
|
throw new EvaluationFailureException();
|
|
if (psrcs != null) PdtEvaluator.Instance.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.Shared.Retrieve(Name)
|
|
));
|
|
if (!comp.Properties.TryGetValue(Name, out SkinProperty result))
|
|
throw new InvalidOperationException(string.Format(
|
|
"Property \"{0}\" not found on component",
|
|
IdentifierManager.Shared.Retrieve(Name)
|
|
));
|
|
return result;
|
|
}
|
|
}
|
|
public class CreateAnchor : SkinPropertyKey {
|
|
public int Name { get; private set; }
|
|
public CreateAnchor(IEnumerable<string> a, int name) : base(a) {
|
|
Name = name;
|
|
}
|
|
public override string ToString() {
|
|
return string.Format("@has {0}", IdentifierManager.Shared.Retrieve(Name));
|
|
}
|
|
public override bool IsValueRequired { get { return false; } }
|
|
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
|
group.RegisterAnchor(Name);
|
|
}
|
|
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
|
throw new InvalidOperationException("Anchor creation in dynamic context is not allowed");
|
|
}
|
|
}
|
|
public class SetAnchor : SkinPropertyKey {
|
|
public int Name { get; private set; }
|
|
public SetAnchor(IEnumerable<string> a, int name) : base(a) {
|
|
Name = name;
|
|
_timeOp = new PropOp.Float(v => _time = v);
|
|
}
|
|
public override string ToString() {
|
|
return string.Format("@at {0}", IdentifierManager.Shared.Retrieve(Name));
|
|
}
|
|
public override bool IsValueRequired { get { return true; } }
|
|
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
|
throw new InvalidOperationException("Setting anchor in static context is not allowed");
|
|
}
|
|
float _time;
|
|
readonly PropOp _timeOp;
|
|
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
|
if (dl != 1) return;
|
|
var psrcs = ctx.ReadContext.PropSrcs;
|
|
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeInsert(psrcs);
|
|
if (!PdtEvaluator.Instance.Evaluate(_timeOp, exp))
|
|
throw new EvaluationFailureException();
|
|
if (psrcs != null) PdtEvaluator.Instance.ContextCascadeDiscard();
|
|
group.PushAnchorEvent(_time, Name);
|
|
}
|
|
}
|
|
public class EmitEffect : SkinPropertyKey {
|
|
public int Name { get; private set; }
|
|
public bool IsSelf { get; private set; }
|
|
public EmitEffect(IEnumerable<string> a, int name, bool isSelf = false) : base(a) {
|
|
Name = name;
|
|
IsSelf = isSelf;
|
|
_op = new PropOp.Float(v => _index = v);
|
|
}
|
|
public override string ToString() {
|
|
return string.Format(IsSelf ? "@emit_self {0}" : "@emit {0}", IdentifierManager.Shared.Retrieve(Name));
|
|
}
|
|
public override bool IsValueRequired { get { return true; } }
|
|
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
|
throw new InvalidOperationException("Emitting effect in static context is not allowed");
|
|
}
|
|
float _index;
|
|
readonly PropOp _op;
|
|
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
|
if (!PdtEvaluator.Instance.Evaluate(_op, exp))
|
|
throw new EvaluationFailureException();
|
|
if (IsSelf) ChartPlayer.effectManager.EmitSelf(Name, _index, ctx.WriteTransform);
|
|
else ChartPlayer.effectManager.Emit(Name, _index);
|
|
}
|
|
}
|
|
public class SetVariable : SkinPropertyKey {
|
|
public int Name { get; private set; }
|
|
public SetVariable(IEnumerable<string> a, int name) : base(a) {
|
|
Name = name;
|
|
}
|
|
public override string ToString() {
|
|
return string.Format("@var {0}", IdentifierManager.Shared.Retrieve(Name));
|
|
}
|
|
public override bool IsValueRequired { get { return true; } }
|
|
public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars) {
|
|
if (!vars.TryGetValue(Name, out PropStores.Float v))
|
|
vars.Add(Name, v = new PropStores.Float());
|
|
if (!PdtEvaluator.Instance.Evaluate(v.Target, exp))
|
|
throw new EvaluationFailureException();
|
|
}
|
|
public override void ExecuteDynamic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp, IntKeyedDictionary<PropStores.Float> vars, int dl) {
|
|
if (!vars.TryGetValue(Name, out PropStores.Float v))
|
|
throw new InvalidOperationException(string.Format("Variable \"{0}\" not defined", IdentifierManager.Shared.Retrieve(Name)));
|
|
if (!PdtEvaluator.Instance.Evaluate(v.Target, exp))
|
|
throw new EvaluationFailureException();
|
|
}
|
|
}
|
|
}
|
|
}
|