From 900bd7b77a3f5d03406dca555b5bf0fb655b1b5f Mon Sep 17 00:00:00 2001 From: PopSlime Date: Sat, 18 Feb 2023 14:51:28 +0800 Subject: [PATCH] Implement effect. --- Assets/Cryville/Crtr/ChartPlayer.cs | 6 ++ Assets/Cryville/Crtr/EffectGroup.cs | 59 ++++++++++++++++++ Assets/Cryville/Crtr/EffectGroup.cs.meta | 11 ++++ Assets/Cryville/Crtr/EffectInstance.cs | 66 +++++++++++++++++++++ Assets/Cryville/Crtr/EffectInstance.cs.meta | 11 ++++ Assets/Cryville/Crtr/EffectManager.cs | 22 +++++++ Assets/Cryville/Crtr/EffectManager.cs.meta | 11 ++++ Assets/Cryville/Crtr/Skin.cs | 4 -- Assets/Cryville/Crtr/SkinPropertyKey.cs | 11 +++- 9 files changed, 194 insertions(+), 7 deletions(-) create mode 100644 Assets/Cryville/Crtr/EffectGroup.cs create mode 100644 Assets/Cryville/Crtr/EffectGroup.cs.meta create mode 100644 Assets/Cryville/Crtr/EffectInstance.cs create mode 100644 Assets/Cryville/Crtr/EffectInstance.cs.meta create mode 100644 Assets/Cryville/Crtr/EffectManager.cs create mode 100644 Assets/Cryville/Crtr/EffectManager.cs.meta diff --git a/Assets/Cryville/Crtr/ChartPlayer.cs b/Assets/Cryville/Crtr/ChartPlayer.cs index 64a7c64..da63e14 100644 --- a/Assets/Cryville/Crtr/ChartPlayer.cs +++ b/Assets/Cryville/Crtr/ChartPlayer.cs @@ -44,6 +44,7 @@ namespace Cryville.Crtr { EventBus nbus; InputProxy inputProxy; Judge judge; + public static EffectManager effectManager; bool started = false; static bool initialized; @@ -160,6 +161,8 @@ namespace Cryville.Crtr { tbus.ForwardStepByTime(renderDist, step); tbus.EndGraphicalUpdate(); UnityEngine.Profiling.Profiler.EndSample(); + + effectManager.Tick(cbus.Time); } catch (Exception ex) { Game.LogException("Game", "An error occured while playing", ex); @@ -496,6 +499,8 @@ namespace Cryville.Crtr { if (tbus != null) { tbus.Dispose(); tbus = null; } if (bbus != null) { bbus.Dispose(); bbus = null; } if (cbus != null) { cbus.Dispose(); cbus.DisposeAll(); cbus = null; } + effectManager.Dispose(); + effectManager = null; etor = null; Logger.Log("main", 1, "Game", "Stopped"); } @@ -638,6 +643,7 @@ namespace Cryville.Crtr { skin.LoadPdt(dir); pskin = skin.Root; pskin.Optimize(etor); + effectManager = new EffectManager(pskin); } #endregion } diff --git a/Assets/Cryville/Crtr/EffectGroup.cs b/Assets/Cryville/Crtr/EffectGroup.cs new file mode 100644 index 0000000..06acfce --- /dev/null +++ b/Assets/Cryville/Crtr/EffectGroup.cs @@ -0,0 +1,59 @@ +using Cryville.Common.Buffers; +using System.Collections.Generic; + +namespace Cryville.Crtr { + public class EffectGroup { + public EffectDefinition Definition { get; private set; } + readonly EffectPool _pool; + class EffectPool : ObjectPool { + readonly List _instances + = new List(); + readonly EffectGroup _group; + public EffectPool(EffectGroup group) : base(256) { + _group = group; + } + protected override EffectInstance Construct() { + var result = new EffectInstance(_group.Definition); + _instances.Add(result); + return result; + } + public void DisposeAll() { + foreach (var i in _instances) i.Dispose(); + } + } + readonly Dictionary _instances + = new Dictionary(); + readonly List _endQueue + = new List(); + public EffectGroup(EffectDefinition def) { + Definition = def; + _pool = new EffectPool(this); + } + double _time; + public void Tick(double time) { + _time = time; + while (_endQueue.Count > 0) { + var item = _endQueue[0]; + if (item.EndTime > _time) break; + item.OnDone(); + _instances.Remove(item.Index); + _pool.Return(item); + _endQueue.RemoveAt(0); + } + } + public void Emit(float index) { + EffectInstance instance; + if (!_instances.TryGetValue(index, out instance)) { + _instances.Add(index, instance = _pool.Rent()); + } + instance.Index = index; + instance.OnEmit(_time); + var i = _endQueue.BinarySearch(instance); + if (i < 0) i = ~i; + _endQueue.Insert(i, instance); + } + public void Dispose() { + _pool.DisposeAll(); + } + } +} diff --git a/Assets/Cryville/Crtr/EffectGroup.cs.meta b/Assets/Cryville/Crtr/EffectGroup.cs.meta new file mode 100644 index 0000000..462e0ab --- /dev/null +++ b/Assets/Cryville/Crtr/EffectGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0d27f9b4383b3445a2a27bfe94173a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Crtr/EffectInstance.cs b/Assets/Cryville/Crtr/EffectInstance.cs new file mode 100644 index 0000000..c19f1da --- /dev/null +++ b/Assets/Cryville/Crtr/EffectInstance.cs @@ -0,0 +1,66 @@ +using Cryville.Common; +using Cryville.Crtr.Components; +using System; +using System.Collections.Generic; +using System.Globalization; +using UnityEngine; + +namespace Cryville.Crtr { + public class EffectInstance : ISkinnableGroup, IComparable { + readonly EffectDefinition _def; + readonly SkinContainer _skinContainer; + public Transform RootTransform { get; private set; } + public EffectInstance(EffectDefinition def) { + _def = def; + _skinContainer = new SkinContainer(_def.elements); + RootTransform = new GameObject("effect:" + GetHashCode().ToString(CultureInfo.InvariantCulture)).transform; + SkinContext = new SkinContext(RootTransform); + ChartPlayer.etor.ContextCascadeInsertBlock(); + _skinContainer.MatchStatic(this); + ChartPlayer.etor.ContextCascadeDiscardBlock(); + foreach (var i in RootTransform.GetComponentsInChildren()) + i.Init(); + _indexSrc = new PropSrc.Float(() => Index); + _durationOp = new PropOp.Float(v => _duration = v); + } + public float Index { get; set; } + static readonly int _var_index = IdentifierManager.SharedInstance.Request("index"); + readonly PropSrc _indexSrc; + double _startTime; + float _duration; + readonly PropOp _durationOp; + public double EndTime { get { return _startTime + _duration; } } + public void OnEmit(double time) { + _startTime = time; + RootTransform.gameObject.SetActive(true); + ChartPlayer.etor.ContextCascadeInsert(); + ChartPlayer.etor.ContextCascadeUpdate(_var_index, _indexSrc); + ChartPlayer.etor.Evaluate(_durationOp, _def.duration); + _skinContainer.MatchDynamic(this, 0); + ChartPlayer.etor.ContextCascadeDiscard(); + } + public void OnDone() { + RootTransform.gameObject.SetActive(false); + } + public void Dispose() { + GameObject.Destroy(RootTransform.gameObject); + } + + public string TypeName { get { throw new InvalidOperationException("Type name undefined"); } } + public SkinContext SkinContext { get; private set; } + public Anchor OpenedAnchor { get { throw new InvalidOperationException("Anchor not supported"); } } + public void PushAnchorEvent(double time, int name) { + throw new InvalidOperationException("Anchor not supported"); + } + public void RegisterAnchor(int name) { + throw new InvalidOperationException("Anchor not supported"); + } + public bool TryGetAnchorsByName(int name, out IReadOnlyCollection result) { + throw new InvalidOperationException("Anchor not supported"); + } + + public int CompareTo(EffectInstance other) { + return EndTime.CompareTo(other.EndTime); + } + } +} diff --git a/Assets/Cryville/Crtr/EffectInstance.cs.meta b/Assets/Cryville/Crtr/EffectInstance.cs.meta new file mode 100644 index 0000000..c4fc6f9 --- /dev/null +++ b/Assets/Cryville/Crtr/EffectInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f442db34239c47046ba1b6fdae8e1216 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Crtr/EffectManager.cs b/Assets/Cryville/Crtr/EffectManager.cs new file mode 100644 index 0000000..3dc55b6 --- /dev/null +++ b/Assets/Cryville/Crtr/EffectManager.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; + +namespace Cryville.Crtr { + public class EffectManager { + readonly Dictionary _groups + = new Dictionary(); + public EffectManager(PdtSkin skin) { + foreach (var e in skin.effects) { + _groups.Add(e.Key.Key, new EffectGroup(e.Value)); + } + } + public void Tick(double time) { + foreach (var g in _groups) g.Value.Tick(time); + } + public void Emit(int id, float index) { + _groups[id].Emit(index); + } + public void Dispose() { + foreach (var g in _groups) g.Value.Dispose(); + } + } +} diff --git a/Assets/Cryville/Crtr/EffectManager.cs.meta b/Assets/Cryville/Crtr/EffectManager.cs.meta new file mode 100644 index 0000000..750bbc7 --- /dev/null +++ b/Assets/Cryville/Crtr/EffectManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 980c0f18a6f491d44a866a85910cb458 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Cryville/Crtr/Skin.cs b/Assets/Cryville/Crtr/Skin.cs index 7efa0b6..880193d 100644 --- a/Assets/Cryville/Crtr/Skin.cs +++ b/Assets/Cryville/Crtr/Skin.cs @@ -59,9 +59,6 @@ namespace Cryville.Crtr { foreach (var e in effects) { var effect = e.Value; etor.ContextCascadeInsert(); - if (effect.args != null) foreach (var i in effect.args) { - etor.ContextCascadeUpdate(i.Key, PropSrc.Error); - } etor.Optimize(effect.duration); effect.elements.Optimize(etor); etor.ContextCascadeDiscard(); @@ -101,7 +98,6 @@ namespace Cryville.Crtr { } public class EffectDefinition { - public Identifier[] args; public PdtExpression duration; public SkinElement elements; } diff --git a/Assets/Cryville/Crtr/SkinPropertyKey.cs b/Assets/Cryville/Crtr/SkinPropertyKey.cs index 6fb24b2..3fd4da0 100644 --- a/Assets/Cryville/Crtr/SkinPropertyKey.cs +++ b/Assets/Cryville/Crtr/SkinPropertyKey.cs @@ -98,16 +98,21 @@ namespace Cryville.Crtr { } public class EmitEffect : SkinPropertyKey { public int Name { get; set; } - public EmitEffect() { } + public EmitEffect() { + _op = new PropOp.Float(v => _index = v); + } public override string ToString() { return string.Format("@emit {0}", IdentifierManager.SharedInstance.Retrieve(Name)); } public override bool IsValueRequired { get { return true; } } public override void ExecuteStatic(ISkinnableGroup group, RuntimeSkinContext ctx, PdtExpression exp) { - // TODO + 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, int dl) { - // TODO + ChartPlayer.etor.Evaluate(_op, exp); + ChartPlayer.effectManager.Emit(Name, _index); } } }