diff --git a/Assets/Editor/EmmyTest.cs b/Assets/Editor/EmmyTest.cs index 0628ffaf..d6464bbc 100644 --- a/Assets/Editor/EmmyTest.cs +++ b/Assets/Editor/EmmyTest.cs @@ -13,14 +13,8 @@ public class EmmyTest : Editor [MenuItem("ArcCreate/TestEmmy/Scenecontrol")] public static void GenerateTestScenecontrolEmmy() { - Assembly scAssembly = Assembly.GetAssembly(typeof(ScenecontrolService)); - var emmy = LuaRunner.GetCommonEmmySharp(); - emmy.AppendAssembly(scAssembly); - emmy.AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("AddScenecontrol")); - emmy.AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("Notify")); - emmy.AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("NotifyWarn")); - emmy.AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("NotifyError")); - emmy.Build(Path.GetDirectoryName(Application.dataPath)); + ScenecontrolLuaEnvironment env = new ScenecontrolLuaEnvironment(); + env.GenerateEmmyLua(Path.Combine(Application.dataPath, "..")); } } } \ No newline at end of file diff --git a/Assets/Editor/ScenecontrolChecks.cs b/Assets/Editor/ScenecontrolChecks.cs new file mode 100644 index 00000000..669f5ea8 --- /dev/null +++ b/Assets/Editor/ScenecontrolChecks.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; +using System.Linq; +using ArcCreate.Gameplay.Scenecontrol; +using ArcCreate.Utility.Animation; +using DG.DOTweenEditor; +using DG.Tweening; +using UnityEditor; +using UnityEngine; + +namespace ArcCreate.EditorScripts +{ + public static class ScenecontrolChecks + { + public const string IOFolder = "Assets/Scripts/Gameplay/Scenecontrol/IO"; + public const string DeserializationFile = IOFolder + "/ScenecontrolDeserialization.cs"; + public const string SerializationFile = IOFolder + "/ScenecontrolSerialization.cs"; + + [InitializeOnLoadMethod] + public static void CheckScenecontrol() + { + var allChannelTypes = TypeCache.GetTypesDerivedFrom<IChannel>(); + + var deser = File.ReadAllText(DeserializationFile); + var ser = File.ReadAllText(SerializationFile); + + foreach (var chanType in allChannelTypes.Where(t => !Attribute.IsDefined(t, typeof(SerializationExemptAttribute)))) + { + var chan = chanType.Name; + + if (!deser.Contains(chan)) + { + Debug.LogError($"Channel type {chanType} is missing deserialization code! Please add it!"); + } + + if (!ser.Contains(chan)) + { + Debug.LogError($"Channel type {chanType} is missing serialization code! Please add it!"); + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Editor/ScenecontrolChecks.cs.meta b/Assets/Editor/ScenecontrolChecks.cs.meta new file mode 100644 index 00000000..1021b1fd --- /dev/null +++ b/Assets/Editor/ScenecontrolChecks.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e8ac28742af86646807db7afb3bdcf1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/Compose/Waveform.mat b/Assets/Materials/Compose/Waveform.mat index 297eb470..f1ffd1cf 100644 --- a/Assets/Materials/Compose/Waveform.mat +++ b/Assets/Materials/Compose/Waveform.mat @@ -72,7 +72,7 @@ Material: - _SmoothnessTextureChannel: 0 - _SpecularHighlights: 1 - _SrcBlend: 1 - - _ToSample: 10478160 + - _ToSample: 14773500 - _UVSec: 0 - _ZWrite: 1 m_Colors: diff --git a/Assets/Prefabs/Gameplay/ScenecontrolNoteIndividual.prefab b/Assets/Prefabs/Gameplay/ScenecontrolNoteIndividual.prefab new file mode 100644 index 00000000..3110e8eb --- /dev/null +++ b/Assets/Prefabs/Gameplay/ScenecontrolNoteIndividual.prefab @@ -0,0 +1,46 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &9148057743627579955 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6791676609819765838} + - component: {fileID: 5835389651473541310} + m_Layer: 0 + m_Name: ScenecontrolNoteIndividual + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6791676609819765838 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9148057743627579955} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5835389651473541310 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9148057743627579955} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 992745bc6c6c41d4f9dbd4512489c76e, type: 3} + m_Name: + m_EditorClassIdentifier: + isPersistent: 1 diff --git a/Assets/Prefabs/Gameplay/ScenecontrolNoteIndividual.prefab.meta b/Assets/Prefabs/Gameplay/ScenecontrolNoteIndividual.prefab.meta new file mode 100644 index 00000000..d2f9217d --- /dev/null +++ b/Assets/Prefabs/Gameplay/ScenecontrolNoteIndividual.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5f66e696345e59a4191b57a5ecf86d21 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/Gameplay.unity b/Assets/Scenes/Gameplay.unity index 851fef6b..972716c3 100644 --- a/Assets/Scenes/Gameplay.unity +++ b/Assets/Scenes/Gameplay.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.37311956, g: 0.3807402, b: 0.35872734, a: 1} + m_IndirectSpecularColor: {r: 0.37311918, g: 0.3807398, b: 0.35872716, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -589,10 +589,11 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Title + m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: c7ac2a5a49fae4b4bb4d928c18726d16, type: 2} - m_sharedMaterial: {fileID: 2100000, guid: 7d94f1e4755948de58fab75d76ecc932, type: 2} + m_fontAsset: {fileID: 11400000, guid: fc246767bf759519bb5f459275194444, type: 2} + m_sharedMaterial: {fileID: 3714936077332224653, guid: fc246767bf759519bb5f459275194444, + type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -616,22 +617,22 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 29 - m_fontSizeBase: 29 + m_fontSize: 36 + m_fontSizeBase: 36 m_fontWeight: 400 - m_enableAutoSizing: 1 - m_fontSizeMin: 20 - m_fontSizeMax: 29 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 m_fontStyle: 0 m_HorizontalAlignment: 1 - m_VerticalAlignment: 512 + m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 m_lineSpacing: 0 m_lineSpacingMax: 0 m_paragraphSpacing: 0 - m_charWidthMaxAdj: 30 + m_charWidthMaxAdj: 0 m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 @@ -2012,7 +2013,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 25, y: -200.00002} + m_AnchoredPosition: {x: 25, y: -200} m_SizeDelta: {x: 300, y: 50} m_Pivot: {x: 0, y: 1} --- !u!114 &377893499 @@ -8281,7 +8282,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 25, y: -200.00002} + m_AnchoredPosition: {x: 25, y: -200} m_SizeDelta: {x: 300, y: 50} m_Pivot: {x: 0, y: 1} --- !u!114 &1409023644 @@ -9401,6 +9402,8 @@ MonoBehaviour: type: 3} GroupPrefab: {fileID: 4044602181011751714, guid: 3a19ff92a7a5f7b529ca21daf779e77a, type: 3} + IndividualPrefab: {fileID: 9148057743627579955, guid: 5f66e696345e59a4191b57a5ecf86d21, + type: 3} DefaultMaterial: {fileID: 2100000, guid: 0077ff23d523e3c18aae9ce29959c184, type: 2} ColorBurnMaterial: {fileID: 2100000, guid: 40f43e7d31b274b3aaf597edb06654e0, type: 2} ColorDodgeMaterial: {fileID: 2100000, guid: 8be0bcbba0ce3e760adfbfe8df96f2ef, type: 2} @@ -11539,10 +11542,11 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Composer + m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: c7ac2a5a49fae4b4bb4d928c18726d16, type: 2} - m_sharedMaterial: {fileID: 2100000, guid: 7d94f1e4755948de58fab75d76ecc932, type: 2} + m_fontAsset: {fileID: 11400000, guid: fc246767bf759519bb5f459275194444, type: 2} + m_sharedMaterial: {fileID: 3714936077332224653, guid: fc246767bf759519bb5f459275194444, + type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -11566,22 +11570,22 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 23 - m_fontSizeBase: 23 + m_fontSize: 36 + m_fontSizeBase: 36 m_fontWeight: 400 - m_enableAutoSizing: 1 + m_enableAutoSizing: 0 m_fontSizeMin: 18 - m_fontSizeMax: 23 + m_fontSizeMax: 72 m_fontStyle: 0 m_HorizontalAlignment: 1 - m_VerticalAlignment: 512 + m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 m_wordSpacing: 0 m_lineSpacing: 0 m_lineSpacingMax: 0 m_paragraphSpacing: 0 - m_charWidthMaxAdj: 50 + m_charWidthMaxAdj: 0 m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 @@ -12406,10 +12410,11 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Future ? + m_text: m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: b7b1b4ddbd331de42ac5353299efdd2d, type: 2} - m_sharedMaterial: {fileID: 2100000, guid: ea4b41747e7d6cd059f99e4c986f0c8a, type: 2} + m_fontAsset: {fileID: 11400000, guid: fc246767bf759519bb5f459275194444, type: 2} + m_sharedMaterial: {fileID: 3714936077332224653, guid: fc246767bf759519bb5f459275194444, + type: 2} m_fontSharedMaterials: [] m_fontMaterial: {fileID: 0} m_fontMaterials: [] @@ -12433,14 +12438,14 @@ MonoBehaviour: m_faceColor: serializedVersion: 2 rgba: 4294967295 - m_fontSize: 25 - m_fontSizeBase: 25 + m_fontSize: 36 + m_fontSizeBase: 36 m_fontWeight: 400 - m_enableAutoSizing: 1 - m_fontSizeMin: 15 - m_fontSizeMax: 25 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 m_fontStyle: 0 - m_HorizontalAlignment: 2 + m_HorizontalAlignment: 1 m_VerticalAlignment: 256 m_textAlignment: 65535 m_characterSpacing: 0 @@ -12448,7 +12453,7 @@ MonoBehaviour: m_lineSpacing: 0 m_lineSpacingMax: 0 m_paragraphSpacing: 0 - m_charWidthMaxAdj: 50 + m_charWidthMaxAdj: 0 m_enableWordWrapping: 1 m_wordWrappingRatios: 0.4 m_overflowMode: 0 diff --git a/Assets/Scripts/Compose/Editing/NoteCreation.cs b/Assets/Scripts/Compose/Editing/NoteCreation.cs index 9408b763..17ff4e82 100644 --- a/Assets/Scripts/Compose/Editing/NoteCreation.cs +++ b/Assets/Scripts/Compose/Editing/NoteCreation.cs @@ -344,7 +344,7 @@ private void Update() float z = cursorPosition.z; GroupProperties groupProperties = Services.Gameplay.Chart.GetTimingGroup(tg).GroupProperties; - Vector3 pos = (groupProperties.FallDirection * z) + new Vector3(ArcFormula.LaneToWorldX(cursorLane), 0, 0); + Vector3 pos = (groupProperties.GetFallDirection() * z) + new Vector3(ArcFormula.LaneToWorldX(cursorLane), 0, 0); Quaternion rot = groupProperties.RotationIndividual; Vector3 scl = groupProperties.ScaleIndividual; @@ -363,11 +363,11 @@ private void Update() previewHold.localScale = scl; break; case CreateNoteMode.Arc: - pos = (groupProperties.FallDirection * z) + new Vector3(cursorPosition.x, 1, 0); + pos = (groupProperties.GetFallDirection() * z) + new Vector3(cursorPosition.x, 1, 0); previewArc.localPosition = pos; break; case CreateNoteMode.Trace: - pos = (groupProperties.FallDirection * z) + new Vector3(cursorPosition.x, 1, 0); + pos = (groupProperties.GetFallDirection() * z) + new Vector3(cursorPosition.x, 1, 0); previewTrace.localPosition = pos; break; case CreateNoteMode.ArcTap: @@ -414,7 +414,7 @@ private void Update() previewArcTap.gameObject.SetActive(true); float worldX = parentArc.WorldXAt(cursorTiming); float worldY = parentArc.WorldYAt(cursorTiming); - pos = (groupProperties.FallDirection * z) + new Vector3(worldX, worldY, 0); + pos = (groupProperties.GetFallDirection() * z) + new Vector3(worldX, worldY, 0); previewArcTap.localPosition = pos; previewArcTap.localRotation = rot; previewArcTap.localScale = scl; diff --git a/Assets/Scripts/Compose/EventsEditor/Scenecontrol/CommandTypes/LuaScenecontrol.cs b/Assets/Scripts/Compose/EventsEditor/Scenecontrol/CommandTypes/LuaScenecontrol.cs index 8d0b4a96..7a8e15a3 100644 --- a/Assets/Scripts/Compose/EventsEditor/Scenecontrol/CommandTypes/LuaScenecontrol.cs +++ b/Assets/Scripts/Compose/EventsEditor/Scenecontrol/CommandTypes/LuaScenecontrol.cs @@ -1,8 +1,10 @@ +using EmmySharp; using MoonSharp.Interpreter; namespace ArcCreate.Compose.EventsEditor { [MoonSharpUserData] + [EmmyAlias("ScenecontrolArgs")] internal class LuaScenecontrol { public int Timing { get; set; } diff --git a/Assets/Scripts/Compose/EventsEditor/Scenecontrol/ScenecontrolLuaEnvironment.cs b/Assets/Scripts/Compose/EventsEditor/Scenecontrol/ScenecontrolLuaEnvironment.cs index 842b0408..ab24df38 100644 --- a/Assets/Scripts/Compose/EventsEditor/Scenecontrol/ScenecontrolLuaEnvironment.cs +++ b/Assets/Scripts/Compose/EventsEditor/Scenecontrol/ScenecontrolLuaEnvironment.cs @@ -7,6 +7,7 @@ using ArcCreate.Gameplay.Data; using ArcCreate.Gameplay.Scenecontrol; using ArcCreate.Utility.Lua; +using EmmySharp; using MoonSharp.Interpreter; using UnityEngine; @@ -47,6 +48,7 @@ public void TestReimport() public void SetupScript(Script script) { script.Globals["Channel"] = new ValueChannelBuilder(); + script.Globals["NoteData"] = new NoteChannelBuilder(); script.Globals["StringChannel"] = new StringChannelBuilder(); script.Globals["TextChannel"] = new TextChannelBuilder(); script.Globals["Trigger"] = new TriggerBuilder(); @@ -65,6 +67,11 @@ public void SetupScript(Script script) return new ConstantChannel((float)dyn.Number); }); + Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.Boolean, typeof(BooleanChannel), dyn => + { + return new BooleanConstantChannel(dyn.CastToBool()); + }); + Script.GlobalOptions.CustomConverters.SetScriptToClrCustomConversion(DataType.String, typeof(StringChannel), dyn => { return StringChannelBuilder.Constant(dyn.String); @@ -84,19 +91,26 @@ public void Rebuild() ExecuteEvents(); } - public void GenerateEmmyLua() + public void GenerateEmmyLua(string file = null) { Assembly scAssembly = Assembly.GetAssembly(typeof(ScenecontrolService)); LuaRunner.GetCommonEmmySharp() + .AppendAlias("ScenecontrolArgs", EmmyType.Table( + ("timing", EmmyType.Integer), + ("timingGroup", EmmyType.Integer), + ("args", EmmyType.Array(EmmyType.Option(EmmyType.Integer, EmmyType.String))))) .AppendAssembly(scAssembly) - .AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("AddScenecontrol")) - .AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("Notify")) - .AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("NotifyWarn")) - .AppendFunction(typeof(ScenecontrolLuaEnvironment).GetMethod("NotifyError")) - .Build(Path.GetDirectoryName(Services.Project.CurrentProject.Path)); + .AppendFunction<ScenecontrolLuaEnvironment>("AddScenecontrol") + .AppendFunction<ScenecontrolLuaEnvironment>("Notify") + .AppendFunction<ScenecontrolLuaEnvironment>("NotifyWarn") + .AppendFunction<ScenecontrolLuaEnvironment>("NotifyError") + .Build(file ?? Path.GetDirectoryName(Services.Project.CurrentProject.Path)); } - public void AddScenecontrol(string name, DynValue argNames, DynValue scDef) + public void AddScenecontrol( + string name, + [EmmyType(typeof(string[]))] DynValue argNames, + [EmmyType("fun(args: ScenecontrolArgs)")] DynValue scDef) { if (scenecontrolTypes.ContainsKey(name)) { diff --git a/Assets/Scripts/Gameplay/Chart/ChartService.cs b/Assets/Scripts/Gameplay/Chart/ChartService.cs index 5bbdcc4d..5bcf4c3c 100644 --- a/Assets/Scripts/Gameplay/Chart/ChartService.cs +++ b/Assets/Scripts/Gameplay/Chart/ChartService.cs @@ -442,12 +442,12 @@ public void UpdateChartJudgement(int currentTiming) } } - public void UpdateChartRender(int currentTiming) + public void UpdateRenderingNotes(int currentTiming) { for (int i = 0; i < timingGroups.Count; i++) { TimingGroup tg = timingGroups[i]; - tg.UpdateGroupRender(currentTiming); + tg.UpdateRenderingNotes(currentTiming); if (i == 0) { @@ -456,6 +456,14 @@ public void UpdateChartRender(int currentTiming) } } + public void Render(int currentTiming) + { + for (int i = 0; i < timingGroups.Count; i++) + { + timingGroups[i].Render(currentTiming); + } + } + public void NotifyEdit() { gameplayData.NotifyChartEdit(); diff --git a/Assets/Scripts/Gameplay/Chart/IChartService.cs b/Assets/Scripts/Gameplay/Chart/IChartService.cs index e81354ce..3d9a1d2f 100644 --- a/Assets/Scripts/Gameplay/Chart/IChartService.cs +++ b/Assets/Scripts/Gameplay/Chart/IChartService.cs @@ -72,11 +72,17 @@ IEnumerable<T> FindEventsWithinRange<T>(int from, int to) /// <param name="currentTiming">The current audio timing.</param> void UpdateChartJudgement(int currentTiming); + /// <summary> + /// Update the lists of which notes are rendering this frame. + /// </summary> + /// <param name="currentTiming">The current audio timing.</param> + void UpdateRenderingNotes(int currentTiming); + /// <summary> /// Update rendering of all notes in the chart. /// </summary> /// <param name="currentTiming">The current audio timing.</param> - void UpdateChartRender(int currentTiming); + void Render(int currentTiming); void NotifyEdit(); } diff --git a/Assets/Scripts/Gameplay/Chart/NoteGroup/ArcNoteGroup.cs b/Assets/Scripts/Gameplay/Chart/NoteGroup/ArcNoteGroup.cs index 4b777efa..700b6bd8 100644 --- a/Assets/Scripts/Gameplay/Chart/NoteGroup/ArcNoteGroup.cs +++ b/Assets/Scripts/Gameplay/Chart/NoteGroup/ArcNoteGroup.cs @@ -6,9 +6,9 @@ namespace ArcCreate.Gameplay.Chart { public class ArcNoteGroup : LongNoteGroup<Arc>, IComparer<Arc> { - public override void UpdateRender(int timing, double floorPosition, GroupProperties groupProperties) + public override void UpdateRenderingNotes(int timing, double floorPosition, GroupProperties groupProperties) { - LastRenderingNotes.Clear(); + RenderingNotes.Clear(); if (Notes.Count == 0 || !groupProperties.Visible) { return; @@ -32,19 +32,13 @@ public override void UpdateRender(int timing, double floorPosition, GroupPropert while (notesInRange.MoveNext()) { var note = notesInRange.Current; - LastRenderingNotes.Add(note); + RenderingNotes.Add(note); note.RecalculateDepth(camera, nearClipPlane, farClipPlane, floorPosition); } - if (LastRenderingNotes.Count < 100) + if (RenderingNotes.Count < 100) { - LastRenderingNotes.Sort(this); - } - - for (int i = LastRenderingNotes.Count - 1; i >= 0; i--) - { - Arc note = LastRenderingNotes[i]; - note.UpdateRender(timing, floorPosition, groupProperties); + RenderingNotes.Sort(this); } } diff --git a/Assets/Scripts/Gameplay/Chart/NoteGroup/LongNoteGroup.cs b/Assets/Scripts/Gameplay/Chart/NoteGroup/LongNoteGroup.cs index 3283e08b..37a88b49 100644 --- a/Assets/Scripts/Gameplay/Chart/NoteGroup/LongNoteGroup.cs +++ b/Assets/Scripts/Gameplay/Chart/NoteGroup/LongNoteGroup.cs @@ -14,13 +14,13 @@ public abstract class LongNoteGroup<Note> : NoteGroup<Note> { private readonly RangeTree<Note> timingTree = new RangeTree<Note>(); private readonly RangeTree<Note> floorPositionTree = new RangeTree<Note>(); - private readonly List<Note> lastRenderingNotes = new List<Note>(); + private readonly List<Note> renderingNotes = new List<Note>(TimingGroup.RenderingNotesPreallocCount); protected RangeTree<Note> TimingTree => timingTree; protected RangeTree<Note> FloorPositionTree => floorPositionTree; - protected List<Note> LastRenderingNotes => lastRenderingNotes; + protected List<Note> RenderingNotes => renderingNotes; public override void UpdateJudgement(int timing, double floorPosition, GroupProperties groupProperties) { @@ -42,9 +42,9 @@ public override void UpdateJudgement(int timing, double floorPosition, GroupProp } } - public override void UpdateRender(int timing, double floorPosition, GroupProperties groupProperties) + public override void UpdateRenderingNotes(int timing, double floorPosition, GroupProperties groupProperties) { - lastRenderingNotes.Clear(); + renderingNotes.Clear(); if (Notes.Count == 0 || !groupProperties.Visible) { return; @@ -64,8 +64,15 @@ public override void UpdateRender(int timing, double floorPosition, GroupPropert while (notesInRange.MoveNext()) { var note = notesInRange.Current; - lastRenderingNotes.Add(note); - note.UpdateRender(timing, floorPosition, groupProperties); + renderingNotes.Add(note); + } + } + + public override void Render(int timing, double floorPosition, GroupProperties groupProperties) + { + for (int i = 0; i < renderingNotes.Count; i++) + { + renderingNotes[i].UpdateRender(timing, floorPosition, groupProperties); } } @@ -168,6 +175,6 @@ public override IEnumerable<Note> FindEventsWithinRange(int from, int to) } } - public override IEnumerable<Note> GetRenderingNotes() => lastRenderingNotes; + public override IReadOnlyList<Note> GetRenderingNotes() => renderingNotes; } } \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Chart/NoteGroup/NoteGroup.cs b/Assets/Scripts/Gameplay/Chart/NoteGroup/NoteGroup.cs index a4e3b858..3be34751 100644 --- a/Assets/Scripts/Gameplay/Chart/NoteGroup/NoteGroup.cs +++ b/Assets/Scripts/Gameplay/Chart/NoteGroup/NoteGroup.cs @@ -153,7 +153,15 @@ public void Update(IEnumerable<Note> notes) /// <param name="timing">The timing value.</param> /// <param name="floorPosition">Floor position value corresponding to the timing value.</param> /// <param name="groupProperties">The group properties of the notes' timing group.</param> - public abstract void UpdateRender(int timing, double floorPosition, GroupProperties groupProperties); + public abstract void UpdateRenderingNotes(int timing, double floorPosition, GroupProperties groupProperties); + + /// <summary> + /// Actually render the notes for this frame. + /// </summary> + /// <param name="timing">The timing value.</param> + /// <param name="floorPosition">Floor position value corresponding to the timing value.</param> + /// <param name="groupProperties">The group properties of the notes' timing group.</param> + public abstract void Render(int timing, double floorPosition, GroupProperties groupProperties); /// <summary> /// Called every time there's a change to the note list. @@ -185,7 +193,7 @@ public void Update(IEnumerable<Note> notes) /// Find all rendering notes. /// </summary> /// <returns>List of rendering notes.</returns> - public abstract IEnumerable<Note> GetRenderingNotes(); + public abstract IReadOnlyList<Note> GetRenderingNotes(); /// <summary> /// Called after notes are loaded into the group. diff --git a/Assets/Scripts/Gameplay/Chart/NoteGroup/ShortNoteGroup.cs b/Assets/Scripts/Gameplay/Chart/NoteGroup/ShortNoteGroup.cs index d539c3da..3f0e6bb1 100644 --- a/Assets/Scripts/Gameplay/Chart/NoteGroup/ShortNoteGroup.cs +++ b/Assets/Scripts/Gameplay/Chart/NoteGroup/ShortNoteGroup.cs @@ -14,7 +14,7 @@ public abstract class ShortNoteGroup<Note> : NoteGroup<Note> { private CachedBisect<Note, int> timingSearch; private CachedBisect<Note, double> floorPositionSearch; - private readonly List<Note> lastRenderingNotes = new List<Note>(); + private readonly List<Note> renderingNotes = new List<Note>(TimingGroup.RenderingNotesPreallocCount); public override int ComboAt(int timing) { @@ -44,9 +44,9 @@ public override void UpdateJudgement(int timing, double floorPosition, GroupProp } } - public override void UpdateRender(int timing, double floorPosition, GroupProperties groupProperties) + public override void UpdateRenderingNotes(int timing, double floorPosition, GroupProperties groupProperties) { - lastRenderingNotes.Clear(); + renderingNotes.Clear(); if (Notes.Count == 0 || !groupProperties.Visible) { return; @@ -71,12 +71,19 @@ public override void UpdateRender(int timing, double floorPosition, GroupPropert break; } - note.UpdateRender(timing, floorPosition, groupProperties); - lastRenderingNotes.Add(note); + renderingNotes.Add(note); renderIndex++; } } + public override void Render(int timing, double floorPosition, GroupProperties groupProperties) + { + for (int i = 0; i < renderingNotes.Count; i++) + { + renderingNotes[i].UpdateRender(timing, floorPosition, groupProperties); + } + } + public override void RebuildList() { timingSearch = new CachedBisect<Note, int>(Notes, note => note.Timing); @@ -123,6 +130,6 @@ public override IEnumerable<Note> FindEventsWithinRange(int from, int to) } } - public override IEnumerable<Note> GetRenderingNotes() => lastRenderingNotes; + public override IReadOnlyList<Note> GetRenderingNotes() => renderingNotes; } } \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Chart/TimingGroup.Dispatch.cs b/Assets/Scripts/Gameplay/Chart/TimingGroup.Dispatch.cs index 52aa721a..995e4f6f 100644 --- a/Assets/Scripts/Gameplay/Chart/TimingGroup.Dispatch.cs +++ b/Assets/Scripts/Gameplay/Chart/TimingGroup.Dispatch.cs @@ -2,6 +2,7 @@ using System.Linq; using ArcCreate.ChartFormat; using ArcCreate.Gameplay.Data; +using ArcCreate.Utility.Extension; namespace ArcCreate.Gameplay.Chart { @@ -10,12 +11,16 @@ namespace ArcCreate.Gameplay.Chart /// </summary> public partial class TimingGroup { + public const int RenderingNotesPreallocCount = 40; + private TapNoteGroup taps; private HoldNoteGroup holds; private ArcNoteGroup arcs; private ArcTapNoteGroup arcTaps; private GroupProperties groupProperties; + private readonly List<Note> renderingNotes = new List<Note>(RenderingNotesPreallocCount * 4); + public TimingGroup(int tg) { GroupNumber = tg; @@ -29,6 +34,49 @@ public TimingGroup(int tg) public bool IsVisible { get; set; } = true; + /// <summary> + /// Enable note-individual parameter overrides for this timing group. + /// </summary> + public void EnableIndividualOverrides() + { + GroupProperties.IndividualOverrides.Enable(this); + } + + /// <summary> + /// Disable note-individual parameter overrides for this timing group. + /// </summary> + public void DisableIndividualOverrides() + { + GroupProperties.IndividualOverrides.Disable(); + } + + /// <summary> + /// Get a temporary enumerable of every note in this timing group. + /// </summary> + /// <returns>The temporary enumerable.</returns> + public IEnumerable<Note> GetAllNotes() + { + foreach (var tap in taps.Notes) + { + yield return tap; + } + + foreach (var hold in holds.Notes) + { + yield return hold; + } + + foreach (var arctap in arcTaps.Notes) + { + yield return arctap; + } + + foreach (var arc in arcs.Notes) + { + yield return arc; + } + } + /// <summary> /// Load a timing group data representation into this instance. /// </summary> @@ -67,6 +115,7 @@ public void Load() arcTaps = new ArcTapNoteGroup(); groupProperties = new GroupProperties(); + timings = new List<TimingEvent> { new TimingEvent @@ -107,7 +156,7 @@ public void UpdateGroupJudgement(int timing) arcTaps.UpdateJudgement(timing, floorPosition, groupProperties); } - public void UpdateGroupRender(int timing) + public void UpdateRenderingNotes(int timing) { if (!IsVisible) { @@ -115,10 +164,30 @@ public void UpdateGroupRender(int timing) } double floorPosition = GetFloorPosition(timing); - taps.UpdateRender(timing, floorPosition, groupProperties); - holds.UpdateRender(timing, floorPosition, groupProperties); - arcs.UpdateRender(timing, floorPosition, groupProperties); - arcTaps.UpdateRender(timing, floorPosition, groupProperties); + taps.UpdateRenderingNotes(timing, floorPosition, groupProperties); + holds.UpdateRenderingNotes(timing, floorPosition, groupProperties); + arcs.UpdateRenderingNotes(timing, floorPosition, groupProperties); + arcTaps.UpdateRenderingNotes(timing, floorPosition, groupProperties); + + renderingNotes.Clear(); + renderingNotes.FastAddRange(taps.GetRenderingNotes()); + renderingNotes.FastAddRange(holds.GetRenderingNotes()); + renderingNotes.FastAddRange(arcs.GetRenderingNotes()); + renderingNotes.FastAddRange(arcTaps.GetRenderingNotes()); + } + + public void Render(int timing) + { + if (!IsVisible) + { + return; + } + + double floorPosition = GetFloorPosition(timing); + taps.Render(timing, floorPosition, groupProperties); + holds.Render(timing, floorPosition, groupProperties); + arcs.Render(timing, floorPosition, groupProperties); + arcTaps.Render(timing, floorPosition, groupProperties); } /// <summary> @@ -323,27 +392,7 @@ public IEnumerable<T> FindEventsWithinRange<T>(int from, int to) /// </summary> /// <returns>List of rendering notes.</returns> public IEnumerable<Note> GetRenderingNotes() - { - foreach (var note in taps.GetRenderingNotes()) - { - yield return note; - } - - foreach (var note in holds.GetRenderingNotes()) - { - yield return note; - } - - foreach (var note in arcTaps.GetRenderingNotes()) - { - yield return note; - } - - foreach (var note in arcs.GetRenderingNotes()) - { - yield return note; - } - } + => renderingNotes; /// <summary> /// Clear notes from this timing gruop and destroy all notes. diff --git a/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs b/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs index 70f9617c..ed9bd6c1 100644 --- a/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs +++ b/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs @@ -2,6 +2,7 @@ using ArcCreate.Gameplay.Judgement; using ArcCreate.Gameplay.Render; using ArcCreate.Gameplay.Utility; +using ArcCreate.Utility; using UnityEngine; namespace ArcCreate.Gameplay.Data @@ -137,7 +138,7 @@ public override void GetColliderPosition(int timing, out Vector3 pos, out Vector double fp = TimingGroupInstance.GetFloorPosition(timing); float z = ZPos(fp); Vector3 basePos = new Vector3(ArcFormula.ArcXToWorld(XStart), ArcFormula.ArcYToWorld(YStart), 0); - pos = (TimingGroupInstance.GroupProperties.FallDirection * z) + basePos; + pos = (TimingGroupInstance.GroupProperties.GetFallDirection(this) * z) + basePos; scl = TimingGroupInstance.GroupProperties.ScaleIndividual; } @@ -146,10 +147,12 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr float z = ZPos(currentFloorPosition); Vector3 basePos = new Vector3(ArcFormula.ArcXToWorld(XStart), ArcFormula.ArcYToWorld(YStart), 0); - Vector3 pos = (groupProperties.FallDirection * z) + basePos; - Quaternion rot = groupProperties.RotationIndividual; - Vector3 scl = groupProperties.ScaleIndividual; - Matrix4x4 matrix = groupProperties.GroupMatrix * Matrix4x4.TRS(pos, rot, scl); + TRS noteTransformation = + TRS.TranslateOnly((groupProperties.GetFallDirection(this) * z) + basePos) + + groupProperties.GetNoteTransform(this); + TRS transformation = noteTransformation * groupProperties.GroupTransform; + + Matrix4x4 matrix = transformation.Matrix; float alpha = 1; float redArcValue = Services.Skin.GetRedArcValue(Color); @@ -183,7 +186,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr alpha = EndTiming - Timing <= 1 ? Values.MaxArcAlpha / 2 : Values.MaxArcAlpha; } - Color color = groupProperties.Color; + Color color = groupProperties.GetColor(this); color.a *= Mathf.Min(alpha, arcGroupAlpha); int clipToTiming; @@ -204,7 +207,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr currentFloorPosition, clipToTiming, clipToFloorPosition, - groupProperties.FallDirection, + groupProperties.GetFallDirection(this), z, groupProperties.NoClip); @@ -222,7 +225,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr continue; } - var (bodyMatrix, shadowMatrix) = segment.GetMatrices(currentFloorPosition, groupProperties.FallDirection, z, pos.y); + var (bodyMatrix, shadowMatrix) = segment.GetMatrices(currentFloorPosition, groupProperties.GetFallDirection(this), z, transformation.Translation.y, noteTransformation.Scale); if (IsTrace) { Services.Render.DrawTraceSegment(matrix * bodyMatrix, color, IsSelected); @@ -243,8 +246,8 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr if (!groupProperties.NoHeightIndicator && (clipToTiming <= Timing || groupProperties.NoClip) && ShouldDrawHeightIndicator) { - Matrix4x4 heightIndicatorMatrix = Matrix4x4.Scale(new Vector3(1, pos.y - (Values.TraceMeshOffset / 2), 1)); - Services.Render.DrawHeightIndicator(matrix * heightIndicatorMatrix, heightIndicatorColor * groupProperties.Color); + Matrix4x4 heightIndicatorMatrix = Matrix4x4.Scale(new Vector3(1, transformation.Translation.y - (Values.TraceMeshOffset / 2), 1)); + Services.Render.DrawHeightIndicator(matrix * heightIndicatorMatrix, heightIndicatorColor * color); } if (!groupProperties.NoHead && (clipToTiming <= Timing || groupProperties.NoClip) && IsFirstArcOfGroup) @@ -261,7 +264,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr if (!groupProperties.NoArcCap && shouldDrawArcCap) { - Services.Render.DrawArcCap(arcCap, matrix * arcCapMatrix, arcCapColor * groupProperties.Color, isControllerMode); + Services.Render.DrawArcCap(arcCap, matrix * arcCapMatrix, arcCapColor * color, isControllerMode); } if (currentTiming <= longParticleUntil && currentTiming >= Timing && currentTiming <= EndTiming) @@ -269,7 +272,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr Services.Particle.PlayArcParticle( Color, firstArcOfBranch ?? this, - new Vector3(WorldXAt(currentTiming), WorldYAt(currentTiming), 0)); + new Vector2(ArcXAt(currentTiming), ArcYAt(currentTiming))); } } diff --git a/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs b/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs index 7eaabe36..1c509580 100644 --- a/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs +++ b/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs @@ -25,7 +25,7 @@ public float CalculateZPos(double currentFloorPosition) public float CalculateEndZPos(double currentFloorPosition) => ArcFormula.FloorPositionToZ(EndFloorPosition - currentFloorPosition); - public (Matrix4x4 body, Matrix4x4 shadow) GetMatrices(double floorPosition, Vector3 fallDirection, float baseZ, float baseY) + public (Matrix4x4 body, Matrix4x4 shadow) GetMatrices(double floorPosition, Vector3 fallDirection, float baseZ, float baseY, Vector3 noteScale) { float startZ = ArcFormula.FloorPositionToZ(FloorPosition - floorPosition); float endZ = ArcFormula.FloorPositionToZ(EndFloorPosition - floorPosition); @@ -34,16 +34,22 @@ public float CalculateEndZPos(double currentFloorPosition) startPos = ((endPos - startPos) * From) + startPos; Vector3 dir = endPos - startPos; + startPos.x /= noteScale.x; + startPos.y /= noteScale.y; + + endPos.x /= noteScale.x; + endPos.y /= noteScale.y; + Matrix4x4 bodyMatrix = new Matrix4x4( new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), - new Vector4(dir.x, dir.y, dir.z, 0), + new Vector4(dir.x / noteScale.x, dir.y / noteScale.y, dir.z / noteScale.z, 0), new Vector4(startPos.x, startPos.y, startPos.z, 1)); Matrix4x4 shadowMatrix = new Matrix4x4( new Vector4(1, 0, 0, 0), new Vector4(0, 1, 0, 0), - new Vector4(dir.x, 0, dir.z, 0), + new Vector4(dir.x / noteScale.x, 0, dir.z / noteScale.z, 0), new Vector4(startPos.x, -baseY, startPos.z, 1)); return (bodyMatrix, shadowMatrix); diff --git a/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs b/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs index c28d9cb0..aef27679 100644 --- a/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs +++ b/Assets/Scripts/Gameplay/Data/Events/ArcTap.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using ArcCreate.Gameplay.Judgement; using ArcCreate.Gameplay.Render; +using ArcCreate.Utility; using UnityEngine; namespace ArcCreate.Gameplay.Data @@ -68,7 +69,9 @@ public override void GetColliderPosition(int timing, out Vector3 pos, out Vector double fp = TimingGroupInstance.GetFloorPosition(timing); float z = ZPos(fp); Vector3 basePos = new Vector3(WorldX, WorldY, 0); - pos = (TimingGroupInstance.GroupProperties.FallDirection * z) + basePos; + pos = (TimingGroupInstance.GroupProperties.GetFallDirection(this) * z) + basePos; + + // TODO: this code (and other segments like it) fail to account for per-note data scl = TimingGroupInstance.GroupProperties.ScaleIndividual; } @@ -100,14 +103,16 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr } float z = ZPos(currentFloorPosition); - Vector3 pos = (groupProperties.FallDirection * z) + new Vector3(WorldX, WorldY, 0); - Quaternion rot = groupProperties.RotationIndividual; - Vector3 scl = groupProperties.ScaleIndividual; - Matrix4x4 matrix = groupProperties.GroupMatrix * Matrix4x4.TRS(pos, rot, scl); - Matrix4x4 shadowMatrix = matrix * Matrix4x4.Translate(new Vector3(0, -pos.y, 0)); + TRS noteTransform = + TRS.TranslateOnly((groupProperties.GetFallDirection(this) * z) + new Vector3(WorldX, WorldY, 0)) + + groupProperties.GetNoteTransform(this); + TRS transform = noteTransform * groupProperties.GroupTransform; + + Matrix4x4 matrix = transform.Matrix; + Matrix4x4 shadowMatrix = matrix * Matrix4x4.Translate(new Vector3(0, -transform.Translation.y, 0)); float alpha = ArcFormula.CalculateFadeOutAlpha(z); - Color color = groupProperties.Color; + Color color = groupProperties.GetColor(this); color.a *= alpha; Services.Render.DrawArcTap(isSfx, texture, matrix, color, IsSelected); diff --git a/Assets/Scripts/Gameplay/Data/Events/Hold.cs b/Assets/Scripts/Gameplay/Data/Events/Hold.cs index 12e38d59..376c7b96 100644 --- a/Assets/Scripts/Gameplay/Data/Events/Hold.cs +++ b/Assets/Scripts/Gameplay/Data/Events/Hold.cs @@ -100,7 +100,7 @@ public override void GetColliderPosition(int timing, out Vector3 pos, out Vector float z = ZPos(fp); float endZ = EndZPos(fp); Vector3 basePos = new Vector3(ArcFormula.LaneToWorldX(Lane), 0, 0); - pos = (TimingGroupInstance.GroupProperties.FallDirection * z) + basePos; + pos = (TimingGroupInstance.GroupProperties.GetFallDirection(this) * z) + basePos; scl = TimingGroupInstance.GroupProperties.ScaleIndividual; scl.z *= z - endZ; } @@ -136,12 +136,13 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr float z = ZPos(currentFloorPosition); float endZ = EndZPos(currentFloorPosition); - Vector3 pos = (groupProperties.FallDirection * z) + new Vector3(ArcFormula.LaneToWorldX(Lane), 0, 0); - Quaternion rot = groupProperties.RotationIndividual; - Vector3 scl = groupProperties.ScaleIndividual; - Matrix4x4 matrix = groupProperties.GroupMatrix - * Matrix4x4.TRS(pos, rot, scl) - * MatrixUtility.Shear(groupProperties.FallDirection * (z - endZ)); + + TRS noteTransform = + TRS.TranslateOnly((groupProperties.GetFallDirection(this) * z) + new Vector3(ArcFormula.LaneToWorldX(Lane), 0, 0)) + + groupProperties.GetNoteTransform(this); + TRS transform = noteTransform * groupProperties.GroupTransform; + + Matrix4x4 matrix = transform * MatrixUtility.Shear(groupProperties.GetFallDirection(this) * (z - endZ)); float alpha = 1; if (highlight) @@ -170,7 +171,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr } alpha *= Values.MaxHoldAlpha; - Color color = groupProperties.Color; + Color color = groupProperties.GetColor(this); color.a *= alpha; float from = 0; diff --git a/Assets/Scripts/Gameplay/Data/Events/Tap.cs b/Assets/Scripts/Gameplay/Data/Events/Tap.cs index 450e1909..245d602c 100644 --- a/Assets/Scripts/Gameplay/Data/Events/Tap.cs +++ b/Assets/Scripts/Gameplay/Data/Events/Tap.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using ArcCreate.Gameplay.Judgement; using ArcCreate.Gameplay.Render; +using ArcCreate.Utility; using UnityEngine; namespace ArcCreate.Gameplay.Data @@ -63,7 +64,7 @@ public override void GetColliderPosition(int timing, out Vector3 pos, out Vector { float z = ZPos(TimingGroupInstance.GetFloorPosition(timing)); Vector3 basePos = new Vector3(ArcFormula.LaneToWorldX(Lane), 0, 0); - pos = (TimingGroupInstance.GroupProperties.FallDirection * z) + basePos; + pos = (TimingGroupInstance.GroupProperties.GetFallDirection(this) * z) + basePos; scl = TimingGroupInstance.GroupProperties.ScaleIndividual; scl.z *= ArcFormula.CalculateTapSizeScalar(z); } @@ -91,14 +92,20 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr float z = ZPos(currentFloorPosition); Vector3 basePos = new Vector3(ArcFormula.LaneToWorldX(Lane), 0, 0); - Vector3 pos = (groupProperties.FallDirection * z) + basePos; - Quaternion rot = groupProperties.RotationIndividual; - Vector3 scl = groupProperties.ScaleIndividual; - scl.z *= ArcFormula.CalculateTapSizeScalar(z); - Matrix4x4 matrix = groupProperties.GroupMatrix * Matrix4x4.TRS(pos, rot, scl); + + TRS noteTransform = + TRS.TranslateOnly((groupProperties.GetFallDirection(this) * z) + basePos) + + groupProperties.GetNoteTransform(this); + noteTransform.Scale = new Vector3( + noteTransform.Scale.x, + noteTransform.Scale.y, + noteTransform.Scale.z * ArcFormula.CalculateTapSizeScalar(z)); + + TRS transform = noteTransform * groupProperties.GroupTransform; + Matrix4x4 matrix = transform.Matrix; float alpha = ArcFormula.CalculateFadeOutAlpha(z); - Color color = groupProperties.Color; + Color color = groupProperties.GetColor(this); Color connectionColor = connectionLineColor; color.a *= alpha; connectionColor.a *= alpha; @@ -110,6 +117,9 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr Vector3 arctapPos = new Vector3(arctap.WorldX, arctap.WorldY, 0); Vector3 direction = arctapPos - basePos; + Color thisConnectionColor = connectionColor; + thisConnectionColor.a *= Mathf.Min(color.a, groupProperties.GetColor(arctap).a); + Matrix4x4 lineMatrix = matrix * Matrix4x4.TRS( pos: Vector3.zero, q: Quaternion.LookRotation(direction, Vector3.up), diff --git a/Assets/Scripts/Gameplay/Data/GroupProperties.cs b/Assets/Scripts/Gameplay/Data/GroupProperties.cs index d4ed7fff..939857a8 100644 --- a/Assets/Scripts/Gameplay/Data/GroupProperties.cs +++ b/Assets/Scripts/Gameplay/Data/GroupProperties.cs @@ -1,5 +1,8 @@ +using System; +using System.Runtime.CompilerServices; using ArcCreate.ChartFormat; using ArcCreate.Gameplay.Skin; +using ArcCreate.Utility; using UnityEngine; namespace ArcCreate.Gameplay.Data @@ -80,22 +83,43 @@ public GroupProperties(RawTimingGroup raw) public float SCAngleY { get; set; } = 0; - public Matrix4x4 GroupMatrix { get; set; } = Matrix4x4.identity; + public TRS GroupTransform { get; set; } = TRS.identity; public bool Visible { get; set; } = true; - public Vector3 FallDirection + public NoteIndividualProperties IndividualOverrides { get; set; } = new NoteIndividualProperties(); + + public Vector3 GetFallDirection(Note note = null) { - get - { - float angleXf = 90.0f - AngleX - SCAngleX; - float angleYf = AngleY + SCAngleY; + float angleXf = 90.0f - GetAngleX(note); + float angleYf = GetAngleY(note); - float x = Mathf.Sin(angleXf * Mathf.Deg2Rad) * Mathf.Sin(angleYf * Mathf.Deg2Rad); - float y = -Mathf.Cos(angleXf * Mathf.Deg2Rad); - float z = Mathf.Sin(angleXf * Mathf.Deg2Rad) * Mathf.Cos(angleYf * Mathf.Deg2Rad); - return new Vector3(x, y, z); - } + float x = Mathf.Sin(angleXf * Mathf.Deg2Rad) * Mathf.Sin(angleYf * Mathf.Deg2Rad); + float y = -Mathf.Cos(angleXf * Mathf.Deg2Rad); + float z = Mathf.Sin(angleXf * Mathf.Deg2Rad) * Mathf.Cos(angleYf * Mathf.Deg2Rad); + + return new Vector3(x, y, z); + } + + public Color GetColor(Note note) + { + return Color * GetNIProperty(note, Color.white, ni => ni.UseColor, n => n.Color); + } + + public TRS GetNoteTransform(Note note) + { + return GetNIProperty(note, TRS.identity, ni => ni.UsePosition, n => n.Transform) + + new TRS(default, RotationIndividual, ScaleIndividual); + } + + public float GetAngleX(Note note) + { + return AngleX + SCAngleX + GetNIProperty(note, 0, ni => ni.UseAngle, n => n.Angles.x); + } + + public float GetAngleY(Note note) + { + return AngleY + SCAngleY + GetNIProperty(note, 0, ni => ni.UseAngle, n => n.Angles.y); } public RawTimingGroup ToRaw() @@ -117,5 +141,30 @@ public RawTimingGroup ToRaw() ArcResolution = ArcResolution, }; } + + /// <summary> + /// Get a property which may be overriden on a per-note basis. + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private T GetNIProperty<T>(Note note, T defaultValue, Predicate<NoteIndividualProperties> nienabled, Func<NoteProperties, T> nivalue) + { + if (note is null) + { + return defaultValue; + } + + if (!IndividualOverrides.IsEnabled) + { + return defaultValue; + } + + if (!nienabled(IndividualOverrides)) + { + return defaultValue; + } + + var ni = IndividualOverrides.PropertiesFor(note); + return nivalue(ni); + } } } \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Data/NoteIndividualProperties.cs b/Assets/Scripts/Gameplay/Data/NoteIndividualProperties.cs new file mode 100644 index 00000000..94ceb8ff --- /dev/null +++ b/Assets/Scripts/Gameplay/Data/NoteIndividualProperties.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using ArcCreate.ChartFormat; +using ArcCreate.Gameplay.Chart; +using ArcCreate.Gameplay.Skin; +using ArcCreate.Utility; +using UnityEngine; + +namespace ArcCreate.Gameplay.Data +{ + public class NoteIndividualProperties + { + private Dictionary<Note, NoteProperties> properties; + + public bool IsEnabled => properties != null; + + public bool UseColor { get; set; } = false; + + public bool UsePosition { get; set; } = false; + + public bool UseAngle { get; set; } = false; + + public void Enable(TimingGroup timinggroup) + { + properties = new Dictionary<Note, NoteProperties>(); + + foreach (var note in timinggroup.GetAllNotes()) + { + properties[note] = new NoteProperties(); + } + } + + public void Disable() + { + properties = null; + } + + /// <summary> + /// Get the properties for a given note, which can be modified + /// for use later on. Returns `null` if <see cref="IsEnabled"/> + /// returns false. + /// </summary> + /// <returns>The properties which are associated with a note.</returns> + /// <param name="note">The note to find the properties of.</param> + public NoteProperties PropertiesFor(Note note) + { + if (!IsEnabled) + { + return null; + } + + if (!properties.TryGetValue(note, out var prop)) + { + prop = new NoteProperties(); + properties[note] = prop; + } + + return prop; + } + + public void SetAllColors(Color color) + { + foreach (var props in properties.Values) + { + props.Color = color; + } + } + + public void SetAllTransforms(TRS transform) + { + foreach (var props in properties.Values) + { + props.Transform = transform; + } + } + + public void SetAllAngles(Vector2 xy) + { + foreach (var props in properties.Values) + { + props.Angles = xy; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Data/NoteIndividualProperties.cs.meta b/Assets/Scripts/Gameplay/Data/NoteIndividualProperties.cs.meta new file mode 100644 index 00000000..7faa30a4 --- /dev/null +++ b/Assets/Scripts/Gameplay/Data/NoteIndividualProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7391146f92de24a4ca453d8ff2c7d429 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Data/NoteProperties.cs b/Assets/Scripts/Gameplay/Data/NoteProperties.cs new file mode 100644 index 00000000..1fdc41be --- /dev/null +++ b/Assets/Scripts/Gameplay/Data/NoteProperties.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using ArcCreate.ChartFormat; +using ArcCreate.Gameplay.Skin; +using ArcCreate.Utility; +using UnityEngine; + +namespace ArcCreate.Gameplay.Data +{ + public class NoteProperties + { + public Color Color { get; set; } = Color.white; + + public TRS Transform { get; set; } = TRS.identity; + + public Vector2 Angles { get; set; } = Vector2.zero; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Data/NoteProperties.cs.meta b/Assets/Scripts/Gameplay/Data/NoteProperties.cs.meta new file mode 100644 index 00000000..1b81e14c --- /dev/null +++ b/Assets/Scripts/Gameplay/Data/NoteProperties.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e06d0efdb3319c44a45e2ee98cea2d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/GameplayManager.cs b/Assets/Scripts/Gameplay/GameplayManager.cs index 1787a844..7e7d4972 100644 --- a/Assets/Scripts/Gameplay/GameplayManager.cs +++ b/Assets/Scripts/Gameplay/GameplayManager.cs @@ -143,10 +143,11 @@ private void Update() Services.Chart.UpdateChartJudgement(currentTiming); Services.Judgement.ProcessInput(currentTiming); - Services.Chart.UpdateChartRender(currentTiming); + Services.Chart.UpdateRenderingNotes(currentTiming); Services.Score.UpdateDisplay(currentTiming); Services.Camera.UpdateCamera(currentTiming); Services.Scenecontrol.UpdateScenecontrol(currentTiming); + Services.Chart.Render(currentTiming); Services.Render.UpdateRenderers(); gameplayData.NotifyUpdate(currentTiming); } diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels.meta new file mode 100644 index 00000000..ac3238cf --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1942290d07b96024390ce8857ea25bb0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/AndChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/AndChannel.cs new file mode 100644 index 00000000..3c77a2c5 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/AndChannel.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class AndChannel : BooleanChannel + { + private BooleanChannel a; + private BooleanChannel b; + + public AndChannel() + { + } + + public AndChannel(BooleanChannel a, BooleanChannel b) + { + this.a = a; + this.b = b; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + a = deserialization.GetUnitFromId<BooleanChannel>(properties[0]); + b = deserialization.GetUnitFromId<BooleanChannel>(properties[1]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(a), + serialization.AddUnitAndGetId(b), + }; + } + + public override bool ValueAt(int timing) + => a.ValueAt(timing) && b.ValueAt(timing); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/AndChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/AndChannel.cs.meta new file mode 100644 index 00000000..62fe2590 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/AndChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 152c57fa2acbe5748b9ecf3bcabc9a54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanChannel.cs new file mode 100644 index 00000000..fcc4e263 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanChannel.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using EmmySharp; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [SerializationExempt] + [MoonSharpUserData] + [EmmyDoc("Channel defining a boolean value at any given input timing value")] + public abstract class BooleanChannel : ISerializableUnit, IChannel + { + public abstract bool ValueAt(int timing); + + [MoonSharpHidden] + public abstract List<object> SerializeProperties(ScenecontrolSerialization serialization); + + [MoonSharpHidden] + public abstract void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanChannel.cs.meta new file mode 100644 index 00000000..1e27bfaf --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4948eb5efc7db1e47b87f00c4014ea1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanConstantChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanConstantChannel.cs new file mode 100644 index 00000000..d62a702a --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanConstantChannel.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class BooleanConstantChannel : BooleanChannel + { + private bool value; + + public BooleanConstantChannel() + { + } + + public BooleanConstantChannel(bool value) + { + this.value = value; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + value = (bool)properties[0]; + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + value, + }; + } + + public override bool ValueAt(int timing) + => value; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanConstantChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanConstantChannel.cs.meta new file mode 100644 index 00000000..e7476bd2 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/BooleanConstantChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d65d7a18ebe25a4c93bef5968bebade +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonType.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonType.cs new file mode 100644 index 00000000..447912c3 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonType.cs @@ -0,0 +1,12 @@ +namespace ArcCreate.Gameplay.Scenecontrol +{ + public enum ComparisonType + { + False, + Equals, + GreaterThan, + LessThan, + GreaterEqual, + LessEqual, + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonType.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonType.cs.meta new file mode 100644 index 00000000..438d76f3 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc238786d9110204995a2697293e0e43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonUtilities.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonUtilities.cs new file mode 100644 index 00000000..7e840666 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonUtilities.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + public static class ComparisonUtilities + { + public static bool Compare<T, C>(this ComparisonType type, C comparer, T a, T b) + where C : IComparer<T> + { + var c = comparer.Compare(a, b); + + switch (type) + { + case ComparisonType.Equals: return c == 0; + case ComparisonType.GreaterThan: return c > 0; + case ComparisonType.LessThan: return c < 0; + case ComparisonType.GreaterEqual: return c >= 0; + case ComparisonType.LessEqual: return c <= 0; + + default: return false; + } + } + + public static bool Compare<T>(this ComparisonType type, T a, T b) + where T : IComparable<T> + { + var c = a.CompareTo(b); + + switch (type) + { + case ComparisonType.Equals: return c == 0; + case ComparisonType.GreaterThan: return c > 0; + case ComparisonType.LessThan: return c < 0; + case ComparisonType.GreaterEqual: return c >= 0; + case ComparisonType.LessEqual: return c <= 0; + + default: return false; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonUtilities.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonUtilities.cs.meta new file mode 100644 index 00000000..dc5c92ac --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/ComparisonUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aecc1a1f90a3c90408f927c158e5d6b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NotChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NotChannel.cs new file mode 100644 index 00000000..ce8d4a65 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NotChannel.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NotChannel : BooleanChannel + { + private BooleanChannel a; + + public NotChannel() + { + } + + public NotChannel(BooleanChannel a) + { + this.a = a; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + a = deserialization.GetUnitFromId<BooleanChannel>(properties[0]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(a), + }; + } + + public override bool ValueAt(int timing) + => !a.ValueAt(timing); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NotChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NotChannel.cs.meta new file mode 100644 index 00000000..7443e6e3 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NotChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c9e2de5727024a4a9eede52daaf8301 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NumericalComparisonChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NumericalComparisonChannel.cs new file mode 100644 index 00000000..dc035b90 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NumericalComparisonChannel.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NumericalComparisonChannel : BooleanChannel + { + private ValueChannel a; + private ValueChannel b; + private ComparisonType comparison; + + public NumericalComparisonChannel() + { + } + + public NumericalComparisonChannel(ValueChannel a, ValueChannel b, ComparisonType c) + { + this.a = a; + this.b = b; + comparison = c; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + a = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + b = deserialization.GetUnitFromId<ValueChannel>(properties[1]); + comparison = (ComparisonType)properties[2]; + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(a), + serialization.AddUnitAndGetId(b), + comparison, + }; + } + + public override bool ValueAt(int timing) + => comparison.Compare(a.ValueAt(timing), b.ValueAt(timing)); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NumericalComparisonChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NumericalComparisonChannel.cs.meta new file mode 100644 index 00000000..ea40e4e1 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/NumericalComparisonChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70a78767ec27e224b970a8fd25f0652b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/OrChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/OrChannel.cs new file mode 100644 index 00000000..0b3a3a09 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/OrChannel.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class OrChannel : BooleanChannel + { + private BooleanChannel a; + private BooleanChannel b; + + public OrChannel() + { + } + + public OrChannel(BooleanChannel a, BooleanChannel b) + { + this.a = a; + this.b = b; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + a = deserialization.GetUnitFromId<BooleanChannel>(properties[0]); + b = deserialization.GetUnitFromId<BooleanChannel>(properties[1]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(a), + serialization.AddUnitAndGetId(b), + }; + } + + public override bool ValueAt(int timing) + => a.ValueAt(timing) || b.ValueAt(timing); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/OrChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/OrChannel.cs.meta new file mode 100644 index 00000000..b32e5603 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/OrChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 642be99af590eea4fa960a543aa885a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/StringComparisonChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/StringComparisonChannel.cs new file mode 100644 index 00000000..a6415073 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/StringComparisonChannel.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class StringComparisonChannel : BooleanChannel + { + private StringChannel a; + private StringChannel b; + private ComparisonType comparison; + + public StringComparisonChannel() + { + } + + public StringComparisonChannel(StringChannel a, StringChannel b, ComparisonType c) + { + this.a = a; + this.b = b; + comparison = c; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + a = deserialization.GetUnitFromId<StringChannel>(properties[0]); + b = deserialization.GetUnitFromId<StringChannel>(properties[1]); + comparison = (ComparisonType)properties[2]; + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(a), + serialization.AddUnitAndGetId(b), + comparison, + }; + } + + public override bool ValueAt(int timing) + => comparison.Compare(a.ValueAt(timing), b.ValueAt(timing)); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/StringComparisonChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/StringComparisonChannel.cs.meta new file mode 100644 index 00000000..5d358755 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/BooleanChannels/StringComparisonChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 579d484d1f5ea2f44be28baefdb4ca90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/IChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/IChannel.cs new file mode 100644 index 00000000..164d4fa7 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/IChannel.cs @@ -0,0 +1,6 @@ +namespace ArcCreate.Gameplay.Scenecontrol +{ + public interface IChannel + { + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/IChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/IChannel.cs.meta new file mode 100644 index 00000000..345a1ce0 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/IChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d56ebf1f51b0c14db5b7ebc9757b4ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/AbsChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/AbsChannel.cs new file mode 100644 index 00000000..7737b61a --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/AbsChannel.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; +using UnityEngine; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class AbsChannel : ValueChannel + { + private ValueChannel target; + + public AbsChannel() + { + } + + public AbsChannel(ValueChannel channel) + { + target = channel; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + target = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object> + { + serialization.AddUnitAndGetId(target), + }; + } + + public override float ValueAt(int timing) + { + return Mathf.Abs(target.ValueAt(timing)); + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return target; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/AbsChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/AbsChannel.cs.meta new file mode 100644 index 00000000..8801a04c --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/AbsChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 665e09baef6b5be4f9d731f590f02805 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ChainChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ChainChannel.cs new file mode 100644 index 00000000..b01c6747 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ChainChannel.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class ChainChannel : ValueChannel + { + private ValueChannel outer; + private ValueChannel inner; + + public ChainChannel() + { + } + + public ChainChannel(ValueChannel a, ValueChannel b) + { + this.outer = a; + this.inner = b; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + outer = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + inner = deserialization.GetUnitFromId<ValueChannel>(properties[1]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object> + { + serialization.AddUnitAndGetId(outer), + serialization.AddUnitAndGetId(inner), + }; + } + + public override float ValueAt(int timing) + => outer.ValueAt((int)inner.ValueAt(timing)); + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return outer; + yield return inner; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ChainChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ChainChannel.cs.meta new file mode 100644 index 00000000..94fb4de6 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ChainChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c37e31490ab3fb498b1fae95e37a059 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ClampChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ClampChannel.cs index de573de6..5e9370ff 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ClampChannel.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ClampChannel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using ArcCreate.Gameplay.Data; using MoonSharp.Interpreter; using UnityEngine; diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/IfElseChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/IfElseChannel.cs new file mode 100644 index 00000000..d055a07e --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/IfElseChannel.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class IfElseChannel : ValueChannel + { + private BooleanChannel cond; + private ValueChannel onTrue; + private ValueChannel onFalse; + + public IfElseChannel() + { + } + + public IfElseChannel(BooleanChannel cond, ValueChannel onTrue, ValueChannel onFalse) + { + this.cond = cond; + this.onTrue = onTrue; + this.onFalse = onFalse; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + cond = deserialization.GetUnitFromId<BooleanChannel>(properties[0]); + onTrue = deserialization.GetUnitFromId<ValueChannel>(properties[1]); + onFalse = deserialization.GetUnitFromId<ValueChannel>(properties[2]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object> + { + serialization.AddUnitAndGetId(cond), + serialization.AddUnitAndGetId(onTrue), + serialization.AddUnitAndGetId(onFalse), + }; + } + + public override float ValueAt(int timing) + { + return cond.ValueAt(timing) ? onTrue.ValueAt(timing) : onFalse.ValueAt(timing); + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return onTrue; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/IfElseChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/IfElseChannel.cs.meta new file mode 100644 index 00000000..5469a553 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/IfElseChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a93b1483d5c33344f8959f59d41c6235 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ModuloChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ModuloChannel.cs new file mode 100644 index 00000000..51ae935e --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ModuloChannel.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class ModuloChannel : ValueChannel + { + private ValueChannel a; + private ValueChannel b; + + public ModuloChannel() + { + } + + public ModuloChannel(ValueChannel a, ValueChannel b) + { + this.a = a; + this.b = b; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + a = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + b = deserialization.GetUnitFromId<ValueChannel>(properties[1]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object> + { + serialization.AddUnitAndGetId(a), + serialization.AddUnitAndGetId(b), + }; + } + + public override float ValueAt(int timing) + => a.ValueAt(timing) % b.ValueAt(timing); + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return a; + yield return b; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ModuloChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ModuloChannel.cs.meta new file mode 100644 index 00000000..06bd10e0 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/ModuloChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 351a1ba733a922c46bacb73ffd80e407 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureCosChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureCosChannel.cs new file mode 100644 index 00000000..d467c131 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureCosChannel.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; +using UnityEngine; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class PureCosChannel : ValueChannel + { + private ValueChannel input; + + public PureCosChannel() + { + } + + public PureCosChannel(ValueChannel input) + { + this.input = input; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + input = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(input), + }; + } + + public override float ValueAt(int timing) + { + return Mathf.Cos(input.ValueAt(timing)); + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return input; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureCosChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureCosChannel.cs.meta new file mode 100644 index 00000000..db571ec2 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureCosChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e729a79b4fd03c54981b3db13691bae1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureSineChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureSineChannel.cs new file mode 100644 index 00000000..519cd227 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureSineChannel.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; +using UnityEngine; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class PureSineChannel : ValueChannel + { + private ValueChannel input; + + public PureSineChannel() + { + } + + public PureSineChannel(ValueChannel input) + { + this.input = input; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + input = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>() + { + serialization.AddUnitAndGetId(input), + }; + } + + public override float ValueAt(int timing) + { + return Mathf.Sin(input.ValueAt(timing)); + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return input; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureSineChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureSineChannel.cs.meta new file mode 100644 index 00000000..bca78b7a --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/PureSineChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2731d73fd6bb78946bfb7a0ee49551cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeScaleChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeScaleChannel.cs new file mode 100644 index 00000000..f683d0ec --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeScaleChannel.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class TimeScaleChannel : ValueChannel + { + private ValueChannel value; + private ValueChannel scale; + + public TimeScaleChannel() + { + } + + public TimeScaleChannel(ValueChannel a, ValueChannel b) + { + this.value = a; + this.scale = b; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + value = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + scale = deserialization.GetUnitFromId<ValueChannel>(properties[1]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object> + { + serialization.AddUnitAndGetId(value), + serialization.AddUnitAndGetId(scale), + }; + } + + public override float ValueAt(int timing) + => value.ValueAt(timing * (int)scale.ValueAt(timing)); + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return value; + yield return scale; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeScaleChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeScaleChannel.cs.meta new file mode 100644 index 00000000..12f78352 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeScaleChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7fcc6f4fb7ce3a4b9dc99bae6c28ab6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeShiftChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeShiftChannel.cs new file mode 100644 index 00000000..136a2270 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeShiftChannel.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class TimeShiftChannel : ValueChannel + { + private ValueChannel value; + private ValueChannel shift; + + public TimeShiftChannel() + { + } + + public TimeShiftChannel(ValueChannel a, ValueChannel b) + { + this.value = a; + this.shift = b; + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + value = deserialization.GetUnitFromId<ValueChannel>(properties[0]); + shift = deserialization.GetUnitFromId<ValueChannel>(properties[1]); + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object> + { + serialization.AddUnitAndGetId(value), + serialization.AddUnitAndGetId(shift), + }; + } + + public override float ValueAt(int timing) + => value.ValueAt(timing + (int)shift.ValueAt(timing)); + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield return value; + yield return shift; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeShiftChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeShiftChannel.cs.meta new file mode 100644 index 00000000..9fd8c3a1 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimeShiftChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac08633a05fd5934a990c262b614596e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimingChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimingChannel.cs new file mode 100644 index 00000000..a6f59ab2 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimingChannel.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using ArcCreate.Gameplay.Data; +using MoonSharp.Interpreter; +using UnityEngine; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class TimingChannel : ValueChannel + { + public TimingChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + => timing; + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimingChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimingChannel.cs.meta new file mode 100644 index 00000000..21c705fd --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/MathChannels/TimingChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33b7c5ff69f6b794d9029c480780909b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels.meta new file mode 100644 index 00000000..ba0f698d --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9d49474509046a04f9c8671cd98d44ad +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteChannelBuilder.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteChannelBuilder.cs new file mode 100644 index 00000000..df595ee3 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteChannelBuilder.cs @@ -0,0 +1,48 @@ +using EmmySharp; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + [EmmyAlias("NoteData")] + [EmmyDoc("Class for getting data about notes")] + [EmmySingleton] + public class NoteChannelBuilder + { + [EmmyDoc("Channel which returns the timing of a given node.")] + public static NoteTimingChannel Timing() + => new NoteTimingChannel(); + + [EmmyDoc("Channel which returns the floor-position of a given note.")] + public static NoteFloorPositionChannel FloorPos() + => new NoteFloorPositionChannel(); + + [EmmyDoc("Channel which returns the x-position of a given note at its start time.")] + public static NoteXPositionChannel X() + => new NoteXPositionChannel(); + + [EmmyDoc("Channel which returns the y-position of a given note at its start time.")] + public static NoteYPositionChannel Y() + => new NoteYPositionChannel(); + + [EmmyDoc("Channel which returns the z-position of a given note at its start time.")] + public static NoteZPositionChannel Z() + => new NoteZPositionChannel(); + + [EmmyDoc("Channel which returns the signed time until a given note is started.")] + public static SumChannel Delta() + => Timing() - ValueChannelBuilder.Timing(); + + [EmmyDoc("Channel which returns the signed time until a given note is started.")] + public static NoteIDChannel ID() + => new NoteIDChannel(); + + [EmmyDoc("Channel which returns if a note is an arc")] + public static NoteIsArcChannel IsArc() + => new NoteIsArcChannel(); + + [EmmyDoc("Channel which returns the type of a note")] + public static NoteTypeChannel Type() + => new NoteTypeChannel(); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteChannelBuilder.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteChannelBuilder.cs.meta new file mode 100644 index 00000000..86b4ff16 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteChannelBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8ccd9c80026b5de459675f4e1ef2219e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteFloorPositionChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteFloorPositionChannel.cs new file mode 100644 index 00000000..f22086a7 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteFloorPositionChannel.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteFloorPositionChannel : ValueChannel + { + public NoteFloorPositionChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + => (float?)NoteIndividualController.CurrentNote?.FloorPosition ?? 0; + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteFloorPositionChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteFloorPositionChannel.cs.meta new file mode 100644 index 00000000..17c05dd5 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteFloorPositionChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c9224b62a7f3cf45bc65cccbb9fcefd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIDChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIDChannel.cs new file mode 100644 index 00000000..79b23efd --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIDChannel.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteIDChannel : ValueChannel + { + private static ObjectIDGenerator idGenerator = new ObjectIDGenerator(); + + public NoteIDChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + { + if (NoteIndividualController.CurrentNote == null) + { + return 0; + } + + return idGenerator.GetId(NoteIndividualController.CurrentNote, out _); + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIDChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIDChannel.cs.meta new file mode 100644 index 00000000..3c6bc407 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIDChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7ff9f0726d94744e8dd77e5753052bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIsArcChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIsArcChannel.cs new file mode 100644 index 00000000..92c1fd59 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIsArcChannel.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using ArcCreate.Gameplay.Data; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteIsArcChannel : BooleanChannel + { + public NoteIsArcChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override bool ValueAt(int timing) + => NoteIndividualController.CurrentNote is Arc; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIsArcChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIsArcChannel.cs.meta new file mode 100644 index 00000000..88885561 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteIsArcChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22d2f60edca1866469174237dcc7bd5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTimingChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTimingChannel.cs new file mode 100644 index 00000000..9f9db2cf --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTimingChannel.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteTimingChannel : ValueChannel + { + public NoteTimingChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + => NoteIndividualController.CurrentNote?.Timing ?? 0; + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTimingChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTimingChannel.cs.meta new file mode 100644 index 00000000..73202dcc --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTimingChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a738b871116a4c746945dae0ac16ede2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTypeChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTypeChannel.cs new file mode 100644 index 00000000..8cb0c0b1 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTypeChannel.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using ArcCreate.Gameplay.Data; +using EmmySharp; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteTypeChannel : StringChannel + { + public NoteTypeChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + [return: EmmyType(@"""tap"" | ""hold"" | ""arctap"" | ""arc""")] + public override string ValueAt(int timing) + { + switch (NoteIndividualController.CurrentNote) + { + case Tap t: + return "tap"; + case Hold h: + return "hold"; + case ArcTap at: + return "arctap"; + case Arc a: + return "arc"; + } + + return null; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTypeChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTypeChannel.cs.meta new file mode 100644 index 00000000..038681d6 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteTypeChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af45b2b15a3e40a409c1adc35ef8dee7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteXPositionChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteXPositionChannel.cs new file mode 100644 index 00000000..60d2718c --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteXPositionChannel.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteXPositionChannel : ValueChannel + { + public NoteXPositionChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + { + if (NoteIndividualController.CurrentNote == null) + { + return 0; + } + + return ArcFormula.UnmodifiedWorldPosition(NoteIndividualController.CurrentNote).x; + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteXPositionChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteXPositionChannel.cs.meta new file mode 100644 index 00000000..4b508cae --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteXPositionChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b65a4c1967bbb52429e94b2b89122cd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteYPositionChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteYPositionChannel.cs new file mode 100644 index 00000000..4bcb3887 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteYPositionChannel.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteYPositionChannel : ValueChannel + { + public NoteYPositionChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + { + if (NoteIndividualController.CurrentNote == null) + { + return 0; + } + + return ArcFormula.UnmodifiedWorldPosition(NoteIndividualController.CurrentNote).y; + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteYPositionChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteYPositionChannel.cs.meta new file mode 100644 index 00000000..b34da2d5 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteYPositionChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 089e404ac27ab89428bfc08614d41806 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteZPositionChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteZPositionChannel.cs new file mode 100644 index 00000000..5cbb0cd9 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteZPositionChannel.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using MoonSharp.Interpreter; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteZPositionChannel : ValueChannel + { + public NoteZPositionChannel() + { + } + + public override void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) + { + } + + public override List<object> SerializeProperties(ScenecontrolSerialization serialization) + { + return new List<object>(); + } + + public override float ValueAt(int timing) + { + if (NoteIndividualController.CurrentNote == null) + { + return 0; + } + + return NoteIndividualController.CurrentNote.ZPos( + NoteIndividualController.CurrentNote.TimingGroupInstance.GetFloorPosition(timing)); + } + + protected override IEnumerable<ValueChannel> GetChildrenChannels() + { + yield break; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteZPositionChannel.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteZPositionChannel.cs.meta new file mode 100644 index 00000000..5f8a44ba --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/NoteChannels/NoteZPositionChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b587686ef898b8e41a00ab388027d20f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/StringChannels/StringChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/StringChannels/StringChannel.cs index 310e0c11..98110b82 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/Channels/StringChannels/StringChannel.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/StringChannels/StringChannel.cs @@ -6,7 +6,7 @@ namespace ArcCreate.Gameplay.Scenecontrol { [MoonSharpUserData] [EmmyDoc("Channel defining a string value at any given input timing value")] - public abstract class StringChannel : ISerializableUnit + public abstract class StringChannel : ISerializableUnit, IChannel { public abstract string ValueAt(int timing); diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/TextChannels/TextChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/TextChannels/TextChannel.cs index e9632420..ee2570dc 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/Channels/TextChannels/TextChannel.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/TextChannels/TextChannel.cs @@ -6,7 +6,7 @@ namespace ArcCreate.Gameplay.Scenecontrol { [MoonSharpUserData] [EmmyDoc("Channel defining text at any given input value. Used for controlling TextController's text content")] - public abstract class TextChannel : ISerializableUnit + public abstract class TextChannel : ISerializableUnit, IChannel { public abstract int MaxLength { get; } diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannel.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannel.cs index b9710edd..fe6c8203 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannel.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannel.cs @@ -4,9 +4,10 @@ namespace ArcCreate.Gameplay.Scenecontrol { + [SerializationExempt] [MoonSharpUserData] [EmmyDoc("A generic channel that defines a value for a given input timing value")] - public abstract class ValueChannel : ISerializableUnit + public abstract class ValueChannel : ISerializableUnit, IChannel { [MoonSharpHidden] public static ValueChannel ConstantZeroChannel { get; } = new ConstantChannel(0); @@ -45,6 +46,12 @@ public abstract class ValueChannel : ISerializableUnit public static ProductChannel operator /(ValueChannel a, ValueChannel b) => a * new InverseChannel(b); + public static ModuloChannel operator %(ValueChannel a, ValueChannel b) => new ModuloChannel(a, b); + + public static ModuloChannel operator %(float a, ValueChannel b) => new ModuloChannel(new ConstantChannel(a), b); + + public static ModuloChannel operator %(ValueChannel a, float b) => new ModuloChannel(a, new ConstantChannel(b)); + [EmmyDoc("Gets the value of this channel at the provided timing point")] public abstract float ValueAt(int timing); diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannelBuilder.cs b/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannelBuilder.cs index d1f2a6c0..61e934c0 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannelBuilder.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Channels/ValueChannelBuilder.cs @@ -86,5 +86,73 @@ public static SawChannel Saw( [EmmyDoc("Create a periodic sine channel")] public static SineChannel Sine(ValueChannel period, ValueChannel min, ValueChannel max, ValueChannel offset) => new SineChannel(period, min, max, offset); + + [EmmyDoc("Create a pure sine channel")] + public static PureSineChannel Sine(ValueChannel input) + => new PureSineChannel(input); + + [EmmyDoc("Create a pure cosine channel")] + public static PureCosChannel Cos(ValueChannel input) + => new PureCosChannel(input); + + [EmmyDoc("Create an absolute value channel")] + public static AbsChannel Abs(ValueChannel input) + => new AbsChannel(input); + + [EmmyDoc("Shift the timing input of a channel by another channel's output")] + public static TimeShiftChannel TimeShift(ValueChannel value, ValueChannel shift) + => new TimeShiftChannel(value, shift); + + [EmmyDoc("Scale the timing input of a channel by another channel's output")] + public static TimeScaleChannel TimeScale(ValueChannel value, ValueChannel scale) + => new TimeScaleChannel(value, scale); + + [EmmyDoc("Chain two channels together by sampling the outer channel with the result of the inner")] + public static ChainChannel Chain(ValueChannel outer, ValueChannel inner) + => new ChainChannel(outer, inner); + + [EmmyDoc("Create a channel which returns the current timing")] + public static TimingChannel Timing() + => new TimingChannel(); + + [EmmyDoc("Inverts a boolean channel")] + public static NotChannel Not(BooleanChannel input) + => new NotChannel(input); + + [EmmyDoc("Ands two boolean channel")] + public static AndChannel And(BooleanChannel a, BooleanChannel b) + => new AndChannel(a, b); + + [EmmyDoc("Ors two boolean channel")] + public static OrChannel Or(BooleanChannel a, BooleanChannel b) + => new OrChannel(a, b); + + [EmmyDoc("Checks if two channels are equal")] + public static BooleanChannel Equal(ValueChannel a, ValueChannel b) + => new NumericalComparisonChannel(a, b, ComparisonType.Equals); + + [EmmyDoc("Checks if two string channels are equal")] + public static BooleanChannel Equal(StringChannel a, StringChannel b) + => new StringComparisonChannel(a, b, ComparisonType.Equals); + + [EmmyDoc("Switches between one channel to another based on a condition")] + public static ValueChannel IfElse(BooleanChannel condition, ValueChannel onTrue, ValueChannel onFalse) + => new IfElseChannel(condition, onTrue, onFalse); + + [EmmyDoc("Checks if one channel is greater than another")] + public static BooleanChannel GreaterThan(ValueChannel a, ValueChannel b) + => new NumericalComparisonChannel(a, b, ComparisonType.GreaterThan); + + [EmmyDoc("Checks if one channel is greater than or equal to another")] + public static BooleanChannel GreaterEqual(ValueChannel a, ValueChannel b) + => new NumericalComparisonChannel(a, b, ComparisonType.GreaterEqual); + + [EmmyDoc("Checks if one channel is greater than another")] + public static BooleanChannel LessThan(ValueChannel a, ValueChannel b) + => new NumericalComparisonChannel(a, b, ComparisonType.LessThan); + + [EmmyDoc("Checks if one channel is greater than or equal to another")] + public static BooleanChannel LessEqual(ValueChannel a, ValueChannel b) + => new NumericalComparisonChannel(a, b, ComparisonType.LessEqual); } } \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Controller.cs b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Controller.cs index ad5fd5cf..838aab9b 100755 --- a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Controller.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Controller.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using ArcCreate.Gameplay.Data; using ArcCreate.Utility.Lua; using MoonSharp.Interpreter; using UnityEngine; @@ -129,10 +130,14 @@ public void CopyAllChannelsFrom(Controller controller) txt.EnableTextModule = txt2.EnableTextModule; } + if (this is IAngleController a && controller is IAngleController a2) + { + a.AngleX = a2.AngleX; + a.AngleY = a2.AngleY; + } + if (this is INoteGroupController tg && controller is INoteGroupController tg2) { - tg.AngleX = tg2.AngleX; - tg.AngleY = tg2.AngleY; tg.RotationIndividualX = tg2.RotationIndividualX; tg.RotationIndividualY = tg2.RotationIndividualY; tg.RotationIndividualZ = tg2.RotationIndividualZ; @@ -192,63 +197,90 @@ public virtual void UpdateController(int timing) return; } - if (this is IPositionController pos && pos.EnablePositionModule) + // Potentially individual updates + void UpdateMaybeIndividual() { - Vector3 translation = pos.DefaultTranslation; - Vector3 rotation = pos.DefaultRotation.eulerAngles; - Vector3 scale = pos.DefaultScale; + if (this is IPositionController pos && pos.EnablePositionModule) + { + Vector3 translation = pos.DefaultTranslation; + Vector3 rotation = pos.DefaultRotation.eulerAngles; + Vector3 scale = pos.DefaultScale; - translation.x = pos.TranslationX.ValueAt(timing); - translation.y = pos.TranslationY.ValueAt(timing); - translation.z = pos.TranslationZ.ValueAt(timing); + translation.x = pos.TranslationX.ValueAt(timing); + translation.y = pos.TranslationY.ValueAt(timing); + translation.z = pos.TranslationZ.ValueAt(timing); - rotation.x = pos.RotationX.ValueAt(timing); - rotation.y = pos.RotationY.ValueAt(timing); - rotation.z = pos.RotationZ.ValueAt(timing); + rotation.x = pos.RotationX.ValueAt(timing); + rotation.y = pos.RotationY.ValueAt(timing); + rotation.z = pos.RotationZ.ValueAt(timing); - scale.x = pos.ScaleX.ValueAt(timing); - scale.y = pos.ScaleY.ValueAt(timing); - scale.z = pos.ScaleZ.ValueAt(timing); + scale.x = pos.ScaleX.ValueAt(timing); + scale.y = pos.ScaleY.ValueAt(timing); + scale.z = pos.ScaleZ.ValueAt(timing); - pos.UpdatePosition(translation, Quaternion.Euler(rotation), scale); - } + pos.UpdatePosition(translation, Quaternion.Euler(rotation), scale); + } - if (this is IColorController col && col.EnableColorModule) - { - RGBA color = new RGBA(col.DefaultColor); - HSVA modify = new HSVA(0, 0, 0, 1) + if (this is IColorController col && col.EnableColorModule) + { + RGBA color = new RGBA(col.DefaultColor); + HSVA modify = new HSVA(0, 0, 0, 1) + { + H = col.ColorH.ValueAt(timing), + S = col.ColorS.ValueAt(timing), + V = col.ColorV.ValueAt(timing), + }; + + color.R = col.ColorR.ValueAt(timing); + color.G = col.ColorG.ValueAt(timing); + color.B = col.ColorB.ValueAt(timing); + color.A = col.ColorA.ValueAt(timing); + + HSVA hsva = Convert.RGBAToHSVA(color); + hsva.H = (hsva.H + modify.H) % 360; + hsva.S = Mathf.Clamp(hsva.S + modify.S, 0, 1); + hsva.V = Mathf.Clamp(hsva.V + modify.V, 0, 1); + + col.UpdateColor(Convert.HSVAToRGBA(hsva).ToColor()); + } + + if (this is ILayerController lyr && lyr.EnableLayerModule) { - H = col.ColorH.ValueAt(timing), - S = col.ColorS.ValueAt(timing), - V = col.ColorV.ValueAt(timing), - }; + string layer = lyr.DefaultLayer; + int sort = lyr.DefaultSort; + float alpha = lyr.DefaultAlpha; - color.R = col.ColorR.ValueAt(timing); - color.G = col.ColorG.ValueAt(timing); - color.B = col.ColorB.ValueAt(timing); - color.A = col.ColorA.ValueAt(timing); + layer = lyr.Layer.ValueAt(timing); + sort = (int)lyr.Sort.ValueAt(timing); + alpha = lyr.Alpha.ValueAt(timing) / 255f; - HSVA hsva = Convert.RGBAToHSVA(color); - hsva.H = (hsva.H + modify.H) % 360; - hsva.S = Mathf.Clamp(hsva.S + modify.S, 0, 1); - hsva.V = Mathf.Clamp(hsva.V + modify.V, 0, 1); + lyr.UpdateLayer(layer, sort, alpha); + } - col.UpdateColor(Convert.HSVAToRGBA(hsva).ToColor()); + if (this is IAngleController a && a.EnableAngleModule) + { + float x = a.AngleX.ValueAt(timing); + float y = a.AngleY.ValueAt(timing); + + a.UpdateAngle(x, y); + } } - if (this is ILayerController lyr && lyr.EnableLayerModule) + if (this is INoteIndividualController ni) { - string layer = lyr.DefaultLayer; - int sort = lyr.DefaultSort; - float alpha = lyr.DefaultAlpha; - - layer = lyr.Layer.ValueAt(timing); - sort = (int)lyr.Sort.ValueAt(timing); - alpha = lyr.Alpha.ValueAt(timing) / 255f; - - lyr.UpdateLayer(layer, sort, alpha); + foreach (var note in Services.Chart.GetTimingGroup(ni.GroupNumber).GetRenderingNotes()) + { + NoteIndividualController.CurrentNote = note; + UpdateMaybeIndividual(); + NoteIndividualController.CurrentNote = null; + } + } + else + { + UpdateMaybeIndividual(); } + // Definitely non-individual updates if (this is ITextController txt && txt.EnableTextModule) { float lineSpacing = txt.DefaultLineSpacing; @@ -279,10 +311,7 @@ public virtual void UpdateController(int timing) scale.y = tg.ScaleIndividualY.ValueAt(timing); scale.z = tg.ScaleIndividualZ.ValueAt(timing); - angle.x = tg.AngleX.ValueAt(timing); - angle.y = tg.AngleY.ValueAt(timing); - - tg.UpdateNoteGroup(Quaternion.Euler(rotation), scale, angle); + tg.UpdateNoteGroup(Quaternion.Euler(rotation), scale); } if (this is ICameraController cam && cam.EnableCameraModule) @@ -354,6 +383,7 @@ public virtual void Reset() { Active = new ConstantChannel(DefaultActive ? 1 : 0); SetActive(DefaultActive); + if (this is IPositionController pos) { pos.UpdatePosition(pos.DefaultTranslation, pos.DefaultRotation, pos.DefaultScale); @@ -405,11 +435,16 @@ public virtual void Reset() txt.EnableTextModule = false; } + if (this is IAngleController a) + { + a.UpdateAngle(0, 0); + a.AngleX = new ConstantChannel(0); + a.AngleY = new ConstantChannel(0); + } + if (this is INoteGroupController tg) { - tg.UpdateNoteGroup(Quaternion.identity, Vector3.one, Vector2.zero); - tg.AngleX = new ConstantChannel(0); - tg.AngleY = new ConstantChannel(0); + tg.UpdateNoteGroup(Quaternion.identity, Vector3.one); tg.RotationIndividualX = new ConstantChannel(0); tg.RotationIndividualY = new ConstantChannel(0); tg.RotationIndividualZ = new ConstantChannel(0); @@ -465,6 +500,7 @@ public virtual void Reset() } } + [MoonSharpHidden] public List<object> SerializeProperties(ScenecontrolSerialization serialization) { List<object> result = new List<object> @@ -516,11 +552,16 @@ public List<object> SerializeProperties(ScenecontrolSerialization serialization) result.Add(txt.CustomFont); } + if (this is IAngleController a) + { + result.Add(a.EnableAngleModule); + result.Add(serialization.AddUnitAndGetId(a.AngleX)); + result.Add(serialization.AddUnitAndGetId(a.AngleY)); + } + if (this is INoteGroupController tg) { result.Add(tg.EnableNoteGroupModule); - result.Add(serialization.AddUnitAndGetId(tg.AngleX)); - result.Add(serialization.AddUnitAndGetId(tg.AngleY)); result.Add(serialization.AddUnitAndGetId(tg.RotationIndividualX)); result.Add(serialization.AddUnitAndGetId(tg.RotationIndividualY)); result.Add(serialization.AddUnitAndGetId(tg.RotationIndividualZ)); @@ -573,6 +614,7 @@ public List<object> SerializeProperties(ScenecontrolSerialization serialization) return result; } + [MoonSharpHidden] public void DeserializeProperties(List<object> properties, ScenecontrolDeserialization deserialization) { customParent = deserialization.GetUnitFromId<Controller>(properties[0]); @@ -632,11 +674,17 @@ public void DeserializeProperties(List<object> properties, ScenecontrolDeseriali txt.EnableTextModule = enable; } + if (this is IAngleController a) + { + bool enable = (bool)properties[offset++]; + a.AngleX = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); + a.AngleY = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); + a.EnableAngleModule = enable; + } + if (this is INoteGroupController tg) { bool enable = (bool)properties[offset++]; - tg.AngleX = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); - tg.AngleY = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); tg.RotationIndividualX = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); tg.RotationIndividualY = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); tg.RotationIndividualZ = deserialization.GetUnitFromId<ValueChannel>(properties[offset++]); diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Interfaces.cs b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Interfaces.cs index 6055c3d0..13724c31 100755 --- a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Interfaces.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Interfaces.cs @@ -10,6 +10,11 @@ public interface IController bool DefaultActive { get; } } + public interface INoteIndividualController : IController + { + int GroupNumber { get; } + } + public interface IPositionController : IController { bool EnablePositionModule { get; set; } @@ -110,14 +115,21 @@ public interface ITextController : IController void ApplyCustomFont(string font); } - public interface INoteGroupController : IController + public interface IAngleController : IController { - bool EnableNoteGroupModule { get; set; } - + bool EnableAngleModule { get; set; } + ValueChannel AngleX { get; set; } ValueChannel AngleY { get; set; } + void UpdateAngle(float x, float y); + } + + public interface INoteGroupController : IController + { + bool EnableNoteGroupModule { get; set; } + ValueChannel RotationIndividualX { get; set; } ValueChannel RotationIndividualY { get; set; } @@ -130,7 +142,7 @@ public interface INoteGroupController : IController ValueChannel ScaleIndividualZ { get; set; } - void UpdateNoteGroup(Quaternion rotation, Vector3 scale, Vector2 angle); + void UpdateNoteGroup(Quaternion rotation, Vector3 scale); } public interface ICameraController : IController diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteGroupController.cs b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteGroupController.cs index 9f2e8f4b..e5987ce1 100755 --- a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteGroupController.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteGroupController.cs @@ -1,4 +1,5 @@ using ArcCreate.Gameplay.Chart; +using ArcCreate.Utility; using EmmySharp; using MoonSharp.Interpreter; using UnityEngine; @@ -7,7 +8,7 @@ namespace ArcCreate.Gameplay.Scenecontrol { [MoonSharpUserData] [EmmyDoc("Controller for a timing group")] - public class NoteGroupController : Controller, IPositionController, INoteGroupController, IColorController + public class NoteGroupController : Controller, IPositionController, INoteGroupController, IColorController, IAngleController { private ValueChannel translationX; private ValueChannel translationY; @@ -132,7 +133,7 @@ public ValueChannel AngleX set { angleX = value; - EnableNoteGroupModule = true; + EnableAngleModule = true; } } @@ -142,7 +143,7 @@ public ValueChannel AngleY set { angleY = value; - EnableNoteGroupModule = true; + EnableAngleModule = true; } } @@ -290,6 +291,8 @@ public ValueChannel ColorA public bool EnableColorModule { get; set; } + public bool EnableAngleModule { get; set; } + [MoonSharpHidden] public void UpdateColor(Color color) { @@ -297,21 +300,26 @@ public void UpdateColor(Color color) } [MoonSharpHidden] - public void UpdateNoteGroup(Quaternion rotation, Vector3 scale, Vector2 angle) + public void UpdateNoteGroup(Quaternion rotation, Vector3 scale) { - TimingGroup.GroupProperties.SCAngleX = angle.x; - TimingGroup.GroupProperties.SCAngleY = angle.y; TimingGroup.GroupProperties.RotationIndividual = rotation; TimingGroup.GroupProperties.ScaleIndividual = scale; } + [MoonSharpHidden] + public void UpdateAngle(float x, float y) + { + TimingGroup.GroupProperties.SCAngleX = x; + TimingGroup.GroupProperties.SCAngleY = y; + } + [MoonSharpHidden] public void UpdatePosition(Vector3 translation, Quaternion rotation, Vector3 scale) { transform.localPosition = translation; transform.localRotation = rotation; transform.localScale = scale; - TimingGroup.GroupProperties.GroupMatrix = Matrix4x4.TRS(translation, rotation, scale); + TimingGroup.GroupProperties.GroupTransform = new TRS(translation, rotation, scale); } protected override void SetActive(bool active) diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteIndividualController.cs b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteIndividualController.cs new file mode 100644 index 00000000..3c47197b --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteIndividualController.cs @@ -0,0 +1,289 @@ +using ArcCreate.Gameplay.Chart; +using ArcCreate.Gameplay.Data; +using ArcCreate.Utility; +using EmmySharp; +using MoonSharp.Interpreter; +using UnityEngine; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [MoonSharpUserData] + public class NoteIndividualController : Controller, INoteIndividualController, IColorController, IPositionController, IAngleController + { + // Position + private ValueChannel translationX; + private ValueChannel translationY; + private ValueChannel translationZ; + private ValueChannel rotationX; + private ValueChannel rotationY; + private ValueChannel rotationZ; + private ValueChannel scaleX; + private ValueChannel scaleY; + private ValueChannel scaleZ; + + // Angle + private ValueChannel angleX; + private ValueChannel angleY; + + // Color + private ValueChannel colorR; + private ValueChannel colorG; + private ValueChannel colorB; + private ValueChannel colorH; + private ValueChannel colorV; + private ValueChannel colorA; + private ValueChannel colorS; + + public static Note CurrentNote { get; set; } + + public int GroupNumber => TimingGroup.GroupNumber; + + [MoonSharpHidden] public TimingGroup TimingGroup { get; set; } + + public ValueChannel ColorR + { + get => colorR; + set + { + colorR = value; + EnableColorModule = true; + } + } + + public ValueChannel ColorG + { + get => colorG; + set + { + colorG = value; + EnableColorModule = true; + } + } + + public ValueChannel ColorB + { + get => colorB; + set + { + colorB = value; + EnableColorModule = true; + } + } + + public ValueChannel ColorH + { + get => colorH; + set + { + colorH = value; + EnableColorModule = true; + } + } + + public ValueChannel ColorS + { + get => colorS; + set + { + colorS = value; + EnableColorModule = true; + } + } + + public ValueChannel ColorV + { + get => colorV; + set + { + colorV = value; + EnableColorModule = true; + } + } + + public ValueChannel ColorA + { + get => colorA; + set + { + colorA = value; + EnableColorModule = true; + } + } + + public ValueChannel TranslationX + { + get => translationX; + set + { + translationX = value; + EnablePositionModule = true; + } + } + + public ValueChannel TranslationY + { + get => translationY; + set + { + translationY = value; + EnablePositionModule = true; + } + } + + public ValueChannel TranslationZ + { + get => translationZ; + set + { + translationZ = value; + EnablePositionModule = true; + } + } + + public ValueChannel RotationX + { + get => rotationX; + set + { + rotationX = value; + EnablePositionModule = true; + } + } + + public ValueChannel RotationY + { + get => rotationY; + set + { + rotationY = value; + EnablePositionModule = true; + } + } + + public ValueChannel RotationZ + { + get => rotationZ; + set + { + rotationZ = value; + EnablePositionModule = true; + } + } + + public ValueChannel ScaleX + { + get => scaleX; + set + { + scaleX = value; + EnablePositionModule = true; + } + } + + public ValueChannel ScaleY + { + get => scaleY; + set + { + scaleY = value; + EnablePositionModule = true; + } + } + + public ValueChannel ScaleZ + { + get => scaleZ; + set + { + scaleZ = value; + EnablePositionModule = true; + } + } + + public ValueChannel AngleX + { + get => angleX; + set + { + angleX = value; + EnableAngleModule = true; + } + } + + public ValueChannel AngleY + { + get => angleY; + set + { + angleY = value; + EnableAngleModule = true; + } + } + + public bool EnableColorModule { get; set; } + + public bool EnablePositionModule { get; set; } + + public bool EnableAngleModule { get; set; } + + public Color DefaultColor => Color.white; + + public Vector3 DefaultTranslation => Vector3.zero; + + public Quaternion DefaultRotation => Quaternion.identity; + + public Vector3 DefaultScale => Vector3.one; + + [MoonSharpHidden] + private NoteProperties CurrentProperties + { + get + { + return TimingGroup.GroupProperties.IndividualOverrides.PropertiesFor(CurrentNote); + } + } + + [MoonSharpHidden] + public void UpdateColor(Color color) + { + if (CurrentNote is null) + { + TimingGroup.GroupProperties.IndividualOverrides.SetAllColors(color); + return; + } + + TimingGroup.GroupProperties.IndividualOverrides.UseColor = true; + CurrentProperties.Color = color; + } + + [MoonSharpHidden] + public void UpdatePosition(Vector3 translation, Quaternion rotation, Vector3 scale) + { + TRS trs = new TRS(translation, rotation, scale); + + if (CurrentNote is null) + { + TimingGroup.GroupProperties.IndividualOverrides.SetAllTransforms(trs); + return; + } + + TimingGroup.GroupProperties.IndividualOverrides.UsePosition = true; + CurrentProperties.Transform = trs; + } + + [MoonSharpHidden] + public void UpdateAngle(float x, float y) + { + Vector2 angles = new Vector2(x, y); + + if (CurrentNote is null) + { + TimingGroup.GroupProperties.IndividualOverrides.SetAllAngles(angles); + return; + } + + TimingGroup.GroupProperties.IndividualOverrides.UseAngle = true; + CurrentProperties.Angles = angles; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteIndividualController.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteIndividualController.cs.meta new file mode 100644 index 00000000..e2ba7723 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Internal/NoteIndividualController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 992745bc6c6c41d4f9dbd4512489c76e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Scene.cs b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Scene.cs index 8fac469f..c324b506 100755 --- a/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Scene.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/Controllers/Scene.cs @@ -260,6 +260,7 @@ public CanvasController CameraCanvas [MoonSharpHidden] public GameObject SpritePrefab; [MoonSharpHidden] public GameObject TextPrefab; [MoonSharpHidden] public GameObject GroupPrefab; + [MoonSharpHidden] public GameObject IndividualPrefab; [Header("Materials")] [MoonSharpHidden] public Material DefaultMaterial; @@ -295,6 +296,7 @@ public CanvasController CameraCanvas private readonly Dictionary<SpriteDefinition, Sprite> spriteCache = new Dictionary<SpriteDefinition, Sprite>(); private readonly Dictionary<int, NoteGroupController> noteGroups = new Dictionary<int, NoteGroupController>(); + private readonly Dictionary<int, NoteIndividualController> noteIndividualGroups = new Dictionary<int, NoteIndividualController>(); private readonly List<UniTask<Sprite>> spriteTasks = new List<UniTask<Sprite>>(); private CancellationTokenSource cts = new CancellationTokenSource(); @@ -322,6 +324,7 @@ public void ClearCache() spriteCache.Clear(); noteGroups.Clear(); + noteIndividualGroups.Clear(); } [MoonSharpHidden] @@ -516,6 +519,33 @@ public NoteGroupController GetNoteGroup(int tg) } } + [EmmyDoc("Creates a note individual controller for a timing group")] + public NoteIndividualController GetNoteIndividual(int tg) + { + if (noteIndividualGroups.TryGetValue(tg, out var cached)) + { + return cached; + } + + try + { + var group = Services.Chart.GetTimingGroup(tg); + group.EnableIndividualOverrides(); + NoteIndividualController c = Instantiate(IndividualPrefab, transform).GetComponent<NoteIndividualController>(); + c.TimingGroup = group; + c.SerializedType = $"ni.{group.GroupNumber}"; + c.Start(); + Services.Scenecontrol.AddReferencedController(c); + noteIndividualGroups.Add(group.GroupNumber, c); + return c; + } + catch (Exception e) + { + Debug.LogException(e); + return null; + } + } + [MoonSharpHidden] public Controller CreateFromTypeName(string type) { @@ -706,6 +736,8 @@ private Controller GetBaseControlerFromTypeName(string def, string arg) return CameraCanvas; case "tg": return GetNoteGroup(int.Parse(arg)); + case "ni": + return GetNoteIndividual(int.Parse(arg)); default: return null; } diff --git a/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolDeserialization.cs b/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolDeserialization.cs index bca4d0c6..db14b750 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolDeserialization.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolDeserialization.cs @@ -92,6 +92,42 @@ public ISerializableUnit GetUnitFromType(string type) return new SineChannel(); case "channel.sum": return new SumChannel(); + case "channel.timing": + return new TimingChannel(); + case "channel.puresine": + return new PureSineChannel(); + case "channel.purecos": + return new PureCosChannel(); + case "channel.modulo": + return new ModuloChannel(); + case "channel.abs": + return new AbsChannel(); + case "channel.time.shift": + return new TimeShiftChannel(); + case "channel.time.scale": + return new TimeScaleChannel(); + case "channel.chain": + return new ChainChannel(); + case "channel.ifelse": + return new IfElseChannel(); + + // Note channels + case "channel.note.timing": + return new NoteTimingChannel(); + case "channel.note.floorpos": + return new NoteFloorPositionChannel(); + case "channel.note.x": + return new NoteXPositionChannel(); + case "channel.note.y": + return new NoteYPositionChannel(); + case "channel.note.z": + return new NoteZPositionChannel(); + case "channel.note.id": + return new NoteIDChannel(); + case "channel.note.isarc": + return new NoteIsArcChannel(); + case "channel.note.type": + return new NoteTypeChannel(); // Triggers channels case "channel.trigger.accumulate": @@ -115,6 +151,20 @@ public ISerializableUnit GetUnitFromType(string type) case "channel.text.value": return new ValueToTextChannel(); + // Boolean channels + case "channel.bool.constant": + return new BooleanConstantChannel(); + case "channel.bool.not": + return new NotChannel(); + case "channel.bool.and": + return new AndChannel(); + case "channel.bool.or": + return new OrChannel(); + case "channel.bool.comp.num": + return new NumericalComparisonChannel(); + case "channel.bool.comp.str": + return new StringComparisonChannel(); + // Contexts case "channel.context.droprate": return new DropRateChannel(); diff --git a/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolSerialization.cs b/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolSerialization.cs index 48e71c15..2cbd3d2e 100644 --- a/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolSerialization.cs +++ b/Assets/Scripts/Gameplay/Scenecontrol/IO/ScenecontrolSerialization.cs @@ -79,6 +79,42 @@ public string GetTypeFromUnit(ISerializableUnit unit) return "channel.sine"; case SumChannel sum: return "channel.sum"; + case TimingChannel timing: + return "channel.timing"; + case AbsChannel abs: + return "channel.abs"; + case TimeScaleChannel ts: + return "channel.time.scale"; + case TimeShiftChannel tsh: + return "channel.time.shift"; + case PureSineChannel ps: + return "channel.time.chain"; + case ChainChannel chain: + return "channel.puresine"; + case PureCosChannel pc: + return "channel.purecos"; + case ModuloChannel pc: + return "channel.modulo"; + case IfElseChannel ie: + return "channel.ifelse"; + + // Note channels + case NoteTimingChannel nTiming: + return "channel.note.timing"; + case NoteFloorPositionChannel nFP: + return "channel.note.floorpos"; + case NoteXPositionChannel nx: + return "channel.note.x"; + case NoteYPositionChannel ny: + return "channel.note.y"; + case NoteZPositionChannel nz: + return "channel.note.z"; + case NoteIDChannel id: + return "channel.note.id"; + case NoteIsArcChannel arc: + return "channel.note.isarc"; + case NoteTypeChannel type: + return "channel.note.type"; // Trigger channels case AccumulatingTriggerChannel accum: @@ -102,6 +138,20 @@ public string GetTypeFromUnit(ISerializableUnit unit) case ValueToTextChannel valuetext: return "channel.text.value"; + // Boolean channels + case BooleanConstantChannel bconst: + return "channel.bool.constant"; + case NotChannel not: + return "channel.bool.not"; + case AndChannel and: + return "channel.bool.and"; + case OrChannel or: + return "channel.bool.or"; + case NumericalComparisonChannel ncomp: + return "channel.bool.comp.num"; + case StringComparisonChannel scomp: + return "channel.bool.comp.str"; + // Contexts case DropRateChannel droprate: return "channel.context.droprate"; @@ -132,6 +182,7 @@ public string GetTypeFromUnit(ISerializableUnit unit) case ObserveTrigger tobserve: return "trigger.observe"; default: + if (unit is ISceneController controller) { string name = controller?.SerializedType; diff --git a/Assets/Scripts/Gameplay/Scenecontrol/IO/SerializationExemptAttribute.cs b/Assets/Scripts/Gameplay/Scenecontrol/IO/SerializationExemptAttribute.cs new file mode 100644 index 00000000..da81657e --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/IO/SerializationExemptAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace ArcCreate.Gameplay.Scenecontrol +{ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public sealed class SerializationExemptAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Scenecontrol/IO/SerializationExemptAttribute.cs.meta b/Assets/Scripts/Gameplay/Scenecontrol/IO/SerializationExemptAttribute.cs.meta new file mode 100644 index 00000000..a2eed710 --- /dev/null +++ b/Assets/Scripts/Gameplay/Scenecontrol/IO/SerializationExemptAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8cb8e355ac4baa444b2dde6528695bea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Gameplay/Utility/ArcFormula.cs b/Assets/Scripts/Gameplay/Utility/ArcFormula.cs index c369e7d8..5faa7e4e 100644 --- a/Assets/Scripts/Gameplay/Utility/ArcFormula.cs +++ b/Assets/Scripts/Gameplay/Utility/ArcFormula.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using ArcCreate.Gameplay.Data; using UnityEngine; @@ -208,5 +209,24 @@ public static float CalculateArcSegmentLength(int duration, float arcResolution) float length = Values.ArcSegmentLength / arcResolution; return duration < 1000 ? length : length * 2; } + + public static Vector2 UnmodifiedWorldPosition(Note note) + { + switch (note) + { + case Tap t: + return new Vector2(LaneToWorldX(t.Lane), 0); + case Hold h: + return new Vector2(LaneToWorldX(h.Lane), 0); + + case ArcTap at: + return new Vector2(at.WorldX, at.WorldY); + case Arc a: + return new Vector2(a.WorldXAt(a.Timing), a.WorldYAt(a.Timing)); + + default: + throw new InvalidOperationException($"Unknown note type {note.GetType()}"); + } + } } } \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Utility/Values.cs b/Assets/Scripts/Gameplay/Utility/Values.cs index 86df3601..926cb62a 100644 --- a/Assets/Scripts/Gameplay/Utility/Values.cs +++ b/Assets/Scripts/Gameplay/Utility/Values.cs @@ -1,7 +1,9 @@ +using MoonSharp.Interpreter; using UnityEngine; namespace ArcCreate.Gameplay { + [MoonSharpUserData] public static class Values { // Playfield @@ -56,17 +58,17 @@ public static class Values public const int BeatlineThickness = 20; // Judgement - public const int ScoreModifyDelay = 500; - public const int ArcLockDuration = 500; - public const int ArcGraceDuration = 600; - public const int ArcRedFlashCycle = 500; - public const float ComboLostFlashDuration = 0.1f; + [MoonSharpHidden] public const int ScoreModifyDelay = 500; + [MoonSharpHidden] public const int ArcLockDuration = 500; + [MoonSharpHidden] public const int ArcGraceDuration = 600; + [MoonSharpHidden] public const int ArcRedFlashCycle = 500; + [MoonSharpHidden] public const float ComboLostFlashDuration = 0.1f; public const float ArcHitboxX = 1.9f; public const float ArcHitboxY = 2.5f; public const float ArcTapHitboxX = 3.02f; public const float ArcTapHitboxYDown = 3.1f; public const float ArcTapHitboxYUp = 2.5f; - public const float MinLongNoteTimeIncrement = 0.1f; + [MoonSharpHidden] public const float MinLongNoteTimeIncrement = 0.1f; // Camera public const float CameraY = 9f; @@ -80,50 +82,50 @@ public static class Values public const float CameraArcPosScalar = 0.05f; // Strings - public const string EarlyText = "EARLY"; - public const string LateText = "LATE"; - public const string BeatlinePoolName = "beatline"; - public const string TapParticlePoolName = "tapparticle"; - public const string ArcParticlePoolName = "arcparticle"; - public const string HoldParticlePoolName = "holdparticle"; + [MoonSharpHidden] public const string EarlyText = "EARLY"; + [MoonSharpHidden] public const string LateText = "LATE"; + [MoonSharpHidden] public const string BeatlinePoolName = "beatline"; + [MoonSharpHidden] public const string TapParticlePoolName = "tapparticle"; + [MoonSharpHidden] public const string ArcParticlePoolName = "arcparticle"; + [MoonSharpHidden] public const string HoldParticlePoolName = "holdparticle"; // I sure hope no charter will make use of lane -2147483648 - public const int InvalidLane = int.MinValue; + [MoonSharpHidden] public const int InvalidLane = int.MinValue; - public const int DelayBeforeAudioStart = 2000; + [MoonSharpHidden] public const int DelayBeforeAudioStart = 2000; - public const int DelayBeforeAudioResume = 200; + [MoonSharpHidden] public const int DelayBeforeAudioResume = 200; - public static int ChartAudioOffset { get; internal set; } = 0; + [MoonSharpHidden] public static int ChartAudioOffset { get; internal set; } = 0; - public static float BaseBpm { get; set; } = 100; + [MoonSharpHidden] public static float BaseBpm { get; set; } = 100; - public static float TimingPointDensity { get; set; } = 1; + [MoonSharpHidden] public static float TimingPointDensity { get; set; } = 1; - public static Color[] DefaultDifficultyColors { get; set; } = new Color[] { }; + [MoonSharpHidden] public static Color[] DefaultDifficultyColors { get; set; } = new Color[] { }; - public static float LaneFrom { get; set; } = 1; + [MoonSharpHidden] public static float LaneFrom { get; set; } = 1; - public static float LaneTo { get; set; } = 4; + [MoonSharpHidden] public static float LaneTo { get; set; } = 4; - public static bool EnableColliderGeneration { get; set; } = false; + [MoonSharpHidden] public static bool EnableColliderGeneration { get; set; } = false; - public static bool EnableArcRebuildSegment { get; set; } = true; + [MoonSharpHidden] public static bool EnableArcRebuildSegment { get; set; } = true; - public static Vector2 LaneScreenHitboxBase { get; set; } = Vector2.one; + [MoonSharpHidden] public static Vector2 LaneScreenHitboxBase { get; set; } = Vector2.one; - public static Vector2 ScreenSizeBase { get; set; } = Vector2.one; + [MoonSharpHidden] public static Vector2 ScreenSizeBase { get; set; } = Vector2.one; - public static Vector2 ScreenSize { get; set; } = Vector2.one; + [MoonSharpHidden] public static Vector2 ScreenSize { get; set; } = Vector2.one; - public static float LaneScreenHitboxHorizontal => LaneScreenHitboxBase.x * ScreenSize.x / ScreenSizeBase.x; + [MoonSharpHidden] public static float LaneScreenHitboxHorizontal => LaneScreenHitboxBase.x * ScreenSize.x / ScreenSizeBase.x; - public static float LaneScreenHitboxVertical => LaneScreenHitboxBase.y * ScreenSize.y / ScreenSizeBase.y; + [MoonSharpHidden] public static float LaneScreenHitboxVertical => LaneScreenHitboxBase.y * ScreenSize.y / ScreenSizeBase.y; - public static bool EnablePauseMenu { get; internal set; } = true; + [MoonSharpHidden] public static bool EnablePauseMenu { get; internal set; } = true; - public static bool ShouldNotifyOnAudioEnd { get; internal set; } = false; + [MoonSharpHidden] public static bool ShouldNotifyOnAudioEnd { get; internal set; } = false; - public static int RetryCount { get; internal set; } = 0; + [MoonSharpHidden] public static int RetryCount { get; internal set; } = 0; } } \ No newline at end of file diff --git a/Assets/Scripts/Utility/EmmySharp/EmmyHelpers.cs b/Assets/Scripts/Utility/EmmySharp/EmmyHelpers.cs index 5f682784..2c65fa73 100644 --- a/Assets/Scripts/Utility/EmmySharp/EmmyHelpers.cs +++ b/Assets/Scripts/Utility/EmmySharp/EmmyHelpers.cs @@ -4,8 +4,10 @@ /// </summary> using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; +using MoonSharp.Interpreter; namespace EmmySharp { @@ -26,7 +28,7 @@ public static string ToCamelCase(this string self) return self; } - public static T GetAttrOr<T>(this ICustomAttributeProvider attrs) + public static T GetAttrOrNull<T>(this ICustomAttributeProvider attrs) where T : Attribute { if (attrs == null) @@ -45,12 +47,195 @@ public static T GetAttrOr<T>(this ICustomAttributeProvider attrs) } public static string EmmyDoc(this ICustomAttributeProvider p) - => p.GetAttrOr<EmmyDocAttribute>()?.Documentation; + => p.GetAttrOrNull<EmmyDocAttribute>()?.Documentation; - public static string[] EmmyChoice(this ICustomAttributeProvider p) - => p.GetAttrOr<EmmyChoiceAttribute>()?.Values; + public static EmmyType GetEmmyType(this ICustomAttributeProvider p, Type baseType, IReadOnlyDictionary<string, EmmyType> aliases) + { + EmmyType GetTypeNoMod() + { + var typeAttr = p.GetAttrOrNull<EmmyTypeAttribute>(); + + if (typeAttr is null) + { + var choicesAttr = p.GetAttrOrNull<EmmyChoiceAttribute>(); + + if (choicesAttr is null) + { + return EmmyType.From(baseType); + } + else + { + return EmmyType.Option(choicesAttr.Values); + } + } + else + { + if (typeAttr.Raw is null) + { + return EmmyType.From(typeAttr.Type); + } + + return EmmyType.Raw(typeAttr.Raw); + } + } + + var nullable = p.GetAttrOrNull<EmmyNullableAttribute>() != null; + var ret = GetTypeNoMod(); + + if (nullable) + { + ret = EmmyType.Nullable(ret); + } + + return ret; + } + + public static string EmmyName(this ICustomAttributeProvider p, string nameSimple, bool camelCase = false) + { + if (camelCase) + { + nameSimple = nameSimple.ToCamelCase(); + } + + var name = p.EmmyAlias() ?? nameSimple; + + return RenameAvoidKeyword(name); + } + + public static bool Visible(this ICustomAttributeProvider p) + { + var isVisible = true; + + if (p is Type) + { + isVisible = isVisible + && p.GetAttrOrNull<MoonSharpUserDataAttribute>() != null; + } + else if (p is MethodInfo method) + { + var baseMethod = method.GetBaseDefinition(); + + isVisible = isVisible + && (method == baseMethod || baseMethod.Visible()); + } + else + { + List<Type> types = new List<Type>(); + + if (p is FieldInfo field) + { + types.Add(field.FieldType); + } + else if (p is PropertyInfo prop) + { + types.Add(prop.PropertyType); + } + else if (p is MethodInfo method2) + { + types.Add(method2.ReturnType); + types.AddRange(method2.GetParameters().Select(param => param.ParameterType)); + } + else if (p is ParameterInfo param) + { + types.Add(param.ParameterType); + } + + foreach (var t in types) + { + isVisible = isVisible + && EmmyType.From(t) != null; + } + } + + isVisible = isVisible + && p.GetAttrOrNull<MoonSharpHiddenAttribute>() == null + && p.GetAttrOrNull<MoonSharpHideMemberAttribute>() == null; + + return isVisible; + } + + public static string EmmyName<T>(this T p, bool camelCase = false) + where T : MemberInfo, ICustomAttributeProvider + => p.EmmyName(p.Name, camelCase); public static string EmmyAlias(this ICustomAttributeProvider p) - => p.GetAttrOr<EmmyAliasAttribute>()?.Alias; + => p.GetAttrOrNull<EmmyAliasAttribute>()?.Alias + ?? p.GetAttrOrNull<MoonSharpUserDataMetamethodAttribute>()?.Name; + + private static string RenameAvoidKeyword(string name) + { + switch (name) + { + case "and": + case "break": + case "do": + case "else": + case "elseif": + case "end": + case "false": + case "for": + case "function": + case "goto": + case "if": + case "in": + case "local": + case "nil": + case "not": + case "or": + case "repeat": + case "return": + case "then": + case "true": + case "until": + case "while": + return "_" + name; + default: + return name; + } + } + + private static readonly ISet<string> LuaOperators = new HashSet<string> + { + "__eq", + "__lt", + "__le", + + "__unm", + "__add", + "__sub", + "__div", + "__mul", + "__mod", + "__pow", + "__concat", + + "__tostring", + }; + + private static readonly IReadOnlyDictionary<string, string> OperatorMappings = new Dictionary<string, string> + { + { "op_Equality", "__eq" }, + { "op_LessThan", "__lt" }, + { "op_LessThanOrEqual", "__le" }, + { "op_UnaryNegation", "__unm" }, + { "op_Addition", "__add" }, + { "op_Subtraction", "__sub" }, + { "op_Multiply", "__mul" }, + { "op_Division", "__div" }, + { "op_Modulus", "__mod" }, + }; + + public static string GetLuaOperator(string csOp) + { + if (!OperatorMappings.TryGetValue(csOp, out var luaOp)) + { + return null; + } + + return luaOp; + } + + public static bool IsLuaOperator(string luaOp) + => LuaOperators.Contains(luaOp); } } \ No newline at end of file diff --git a/Assets/Scripts/Utility/EmmySharp/EmmyNullableAttribute.cs b/Assets/Scripts/Utility/EmmySharp/EmmyNullableAttribute.cs new file mode 100644 index 00000000..0ddf3c3f --- /dev/null +++ b/Assets/Scripts/Utility/EmmySharp/EmmyNullableAttribute.cs @@ -0,0 +1,14 @@ +/// <summary> +/// EmmySharp, created by Dylan Rafael (floofer++) for use by 0thElement. +/// The below classes help to generate EmmyLua workspace files from MoonSharp classes. +/// </summary> + +using System; + +namespace EmmySharp +{ + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.Property | AttributeTargets.Field)] + public class EmmyNullableAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/Assets/Scripts/Utility/EmmySharp/EmmyNullableAttribute.cs.meta b/Assets/Scripts/Utility/EmmySharp/EmmyNullableAttribute.cs.meta new file mode 100644 index 00000000..567005a7 --- /dev/null +++ b/Assets/Scripts/Utility/EmmySharp/EmmyNullableAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 074e8b4547b99f74a9d06773daccdc43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Utility/EmmySharp/EmmySharpBuilder.cs b/Assets/Scripts/Utility/EmmySharp/EmmySharpBuilder.cs index e9c1eb10..e6d27c5f 100644 --- a/Assets/Scripts/Utility/EmmySharp/EmmySharpBuilder.cs +++ b/Assets/Scripts/Utility/EmmySharp/EmmySharpBuilder.cs @@ -10,12 +10,444 @@ using System.Reflection; using System.Text; using MoonSharp.Interpreter; +using UnityEngine; namespace EmmySharp { + public abstract class EmmyType + { + public virtual IEnumerable<EmmyType> Constituents + { + get + { + yield return this; + } + } + + public static EmmyType From<T>() + => From(typeof(T)); + + public static EmmyType Void + => Raw("nil"); + + public static EmmyType Integer + => Raw("integer"); + + public static EmmyType Float + => Raw("number"); + + public static EmmyType Bool + => Raw("boolean"); + + public static EmmyType String + => Raw("string"); + + public static EmmyType Any + => Raw("any"); + + public static EmmyType From(Type ty) + { + if (ty == typeof(void)) + { + return Void; + } + else if (ty == typeof(short) || ty == typeof(int) || ty == typeof(long) + || ty == typeof(ushort) || ty == typeof(uint) || ty == typeof(ulong)) + { + return Integer; + } + else if (ty == typeof(float) || ty == typeof(double) || ty == typeof(decimal)) + { + return Float; + } + else if (ty == typeof(bool)) + { + return Bool; + } + else if (ty == typeof(string)) + { + return String; + } + else if (ty == typeof(object) || ty == typeof(DynValue)) + { + return Any; + } + else if (ty.IsArray) + { + var inner = From(ty.GetElementType()); + return inner == null ? null : Array(inner); + } + else if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + var inner = From(ty.GetGenericArguments()[0]); + return inner == null ? null : Nullable(inner); + } + else if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(List<>)) + { + var inner = From(ty.GetGenericArguments()[0]); + return inner == null ? null : Array(inner); + } + else if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + var key = From(ty.GetGenericArguments()[0]); + var value = From(ty.GetGenericArguments()[1]); + + if (key == null || value == null) + { + return null; + } + + return Table(key, value); + } + else if (typeof(Delegate).IsAssignableFrom(ty)) + { + var invoke = ty.GetMethod("Invoke"); + var iparams = invoke.GetParameters(); + + if (iparams.Any(p => p.ParameterType == ty)) + { + throw new InvalidOperationException("Cannot create a function type which is self-referential!"); + } + + var ret = From(invoke.ReturnType); + var par = iparams.Select(p => new EmmyValue { Type = From(p.ParameterType), Name = p.Name }) + .ToArray(); + + if (ret == null || par.Any(p => p.Type == null)) + { + return null; + } + + return Function(ret, par); + } + else if (ty.Visible()) + { + return new WrapperType { Type = ty }; + } + + return null; + } + + public static EmmyType Array(EmmyType inner) + { + return new ArrayType { Inner = inner }; + } + + public static EmmyType Nullable(EmmyType inner) + { + return new NullableType { Inner = inner }; + } + + public static EmmyType Table(EmmyType key, EmmyType value) + { + return new TableType { Key = key, Value = value }; + } + + public static EmmyType Table(params (string name, EmmyType type)[] fields) + { + return new TableLiteralType { Fields = fields.ToDictionary(p => p.name, p => p.type) }; + } + + public static EmmyType Alias(string name, EmmyType inner) + { + return new AliasType { Name = name, Inner = inner }; + } + + public static EmmyType Option(params EmmyType[] types) + { + return new OptionType { Options = types }; + } + + public static EmmyType Option(params string[] literals) + { + return Option(literals.Select(Literal).ToArray()); + } + + public static EmmyType Function(EmmyType ret, params EmmyValue[] parameters) + { + return new FunctionType { Return = ret, Parameters = parameters }; + } + + public static EmmyType Function(params EmmyValue[] parameters) + { + return new FunctionType { Return = null, Parameters = parameters }; + } + + public static EmmyType Literal(string s) + { + return new LiteralStringType { Value = s }; + } + + public static EmmyType Raw(string s) + { + return new RawType { Text = s }; + } + + public virtual string GetDefinition() + => string.Empty; + + public abstract override string ToString(); + + private class WrapperType : EmmyType + { + public Type Type { get; set; } + + public override string ToString() + { + return Type.Name; + } + } + + private class AliasType : EmmyType + { + public string Name { get; set; } + + public EmmyType Inner { get; set; } + + public override IEnumerable<EmmyType> Constituents + { + get + { + yield return this; + yield return Inner; + } + } + + public override string GetDefinition() + { + return "---@alias " + Name + " " + Inner.ToString(); + } + + public override string ToString() + { + return Name; + } + } + + private class NullableType : EmmyType + { + public EmmyType Inner { get; set; } + + public override IEnumerable<EmmyType> Constituents + { + get + { + yield return Inner; + } + } + + public override string ToString() + { + return Inner.ToString() + "?"; + } + } + + private class ArrayType : EmmyType + { + public EmmyType Inner { get; set; } + + public override IEnumerable<EmmyType> Constituents + { + get + { + yield return Inner; + } + } + + public override string ToString() + { + return Inner.ToString() + "[]"; + } + } + + private class OptionType : EmmyType + { + public IReadOnlyList<EmmyType> Options { get; set; } + + public override IEnumerable<EmmyType> Constituents + { + get + { + foreach (var item in Options) + { + yield return item; + } + } + } + + public override string ToString() + { + return "(" + string.Join(" | ", Options) + ")"; + } + } + + private class LiteralStringType : EmmyType + { + public string Value { get; set; } + + public override string ToString() + { + return $"\"{Value}\""; + } + } + + private class RawType : EmmyType + { + public string Text { get; set; } + + public override string ToString() + { + return Text; + } + } + + private class TableLiteralType : EmmyType + { + public override IEnumerable<EmmyType> Constituents + { + get + { + foreach (var f in Fields.Values) + { + yield return f; + } + } + } + + public IReadOnlyDictionary<string, EmmyType> Fields { get; set; } + + public override string ToString() + { + return $"{{{string.Join(", ", Fields.Select(kvp => $"{kvp.Key}: {kvp.Value}"))}}}"; + } + } + + private class TableType : EmmyType + { + public override IEnumerable<EmmyType> Constituents + { + get + { + yield return Key; + yield return Value; + } + } + + public EmmyType Key { get; set; } + + public EmmyType Value { get; set; } + + public override string ToString() + { + return $"table<{Key}, {Value}>"; + } + } + + private class FunctionType : EmmyType + { + public override IEnumerable<EmmyType> Constituents + { + get + { + foreach (var v in Parameters) + { + yield return v.Type; + } + + yield return Return; + } + } + + public IReadOnlyList<EmmyValue> Parameters { get; set; } + + public EmmyType Return { get; set; } + + public override string ToString() + { + var ret = "fun(" + string.Join(", ", Parameters.Select(p => p.Name + ": " + p.Type.ToString())) + ")"; + if (Return != null) + { + ret += " : " + Return.ToString(); + } + + return ret; + } + } + } + + public class EmmyValue + { + public string Name { get; set; } + + public string Doc { get; set; } + + public virtual EmmyType Type { get; set; } + + public bool ParamHasDefaultValue { get; set; } + } + + public class EmmyFunction : EmmyValue + { + public IReadOnlyList<EmmyValue> Parameters { get; set; } + + public EmmyType Return { get; set; } + + public override EmmyType Type + { + get => EmmyType.Function(Return, Parameters.ToArray()); + set => throw new InvalidOperationException(); + } + } + + public class EmmyClass + { + public string Doc { get; set; } + + public string Name { get; set; } + + public bool IsStatic { get; set; } + + public bool IsSingleton { get; set; } + + public EmmyClass Base { get; set; } + + public IReadOnlyList<EmmyValue> Members { get; set; } + + public IReadOnlyList<EmmyValue> Statics { get; set; } + } + public class EmmySharpBuilder { - private readonly StringBuilder builder = new StringBuilder(); + private readonly StringBuilder outputBuilder = new StringBuilder(); + + private readonly HashSet<EmmyType> constituentTypes = new HashSet<EmmyType>(); + private readonly Dictionary<Type, EmmyClass> classes = new Dictionary<Type, EmmyClass>(); + private readonly List<EmmyValue> values = new List<EmmyValue>(); + + private readonly Dictionary<string, EmmyType> aliases = new Dictionary<string, EmmyType>(); + + private void Add(EmmyValue value) + { + values.Add(value); + + foreach (var t in value.Type.Constituents) + { + constituentTypes.Add(t); + } + } + + private void Add(Type source, EmmyClass classs) + { + classes[source] = classs; + + foreach (var v in classs.Members.Concat(classs.Statics)) + { + foreach (var t in v.Type.Constituents) + { + constituentTypes.Add(t); + } + } + } /// <summary> /// Get an emmy sharp builder which contains type information about the @@ -36,14 +468,39 @@ public static EmmySharpBuilder ForThisAssembly() /// </summary> /// <returns>The content string.</returns> public override string ToString() - => builder.ToString(); + { + outputBuilder.Clear(); + outputBuilder.AppendLine("---@meta").AppendLine(); + + foreach (var consType in constituentTypes) + { + var definition = consType.GetDefinition(); + + if (!string.IsNullOrEmpty(definition)) + { + outputBuilder.AppendLine(definition).AppendLine(); + } + } + + foreach (var freeValue in values) + { + RenderValue(freeValue); + } + + foreach (var cls in classes.Values) + { + RenderClass(cls); + } + + return outputBuilder.ToString(); + } /// <summary> /// Append documentation. If null is provided, do nothing. /// </summary> /// <param name="doc">The document to append.</param> /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendDoc(string doc) + private EmmySharpBuilder RenderDoc(string doc) { if (doc is null) { @@ -52,7 +509,7 @@ public EmmySharpBuilder AppendDoc(string doc) foreach (var line in doc.Split(Environment.NewLine.ToCharArray())) { - builder.AppendLine("---" + line); + outputBuilder.AppendLine("---" + line); } return this; @@ -62,22 +519,27 @@ public EmmySharpBuilder AppendDoc(string doc) /// Append a static value specification to this builder. /// </summary> /// <param name="value">The value to append.</param> - /// <param name="baseTy">The base type.</param> + /// <param name="baseV">The base value.</param> /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendStaticValue(EmmySharpValue value, Type baseTy = null) + private EmmySharpBuilder RenderValue(EmmyValue value, string baseV = null) { - AppendDoc(value.Doc); - builder.Append("---@type "); - AppendTypeName(value.Type, value.Options); - builder.AppendLine(); + if (value is EmmyFunction f) + { + return RenderFunction(f, baseV); + } - if (baseTy != null) + RenderDoc(value.Doc); + outputBuilder.Append("---@type "); + outputBuilder.Append(value.Type); + outputBuilder.AppendLine(); + + if (baseV != null) { - builder.Append(baseTy.Name + "."); + outputBuilder.Append(baseV + "."); } - builder.AppendLine(value.Name.ToCamelCase() + " = nil"); - builder.AppendLine(); + outputBuilder.AppendLine(value.Name + " = nil"); + outputBuilder.AppendLine(); return this; } @@ -87,12 +549,13 @@ public EmmySharpBuilder AppendStaticValue(EmmySharpValue value, Type baseTy = nu /// </summary> /// <param name="field">The field to append.</param> /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendField(EmmySharpValue field) + private EmmySharpBuilder RenderField(EmmyValue field) { - AppendDoc(field.Doc); - builder.Append("---@field public " + field.Name.ToCamelCase() + " "); - AppendTypeName(field.Type, field.Options); - builder.AppendLine(); + outputBuilder.Append("---@field public " + field.Name + " "); + outputBuilder.Append(field.Type); + outputBuilder.Append(' '); + outputBuilder.Append(field.Doc?.Replace(Environment.NewLine, "\n")); + outputBuilder.AppendLine(); return this; } @@ -100,118 +563,125 @@ public EmmySharpBuilder AppendField(EmmySharpValue field) /// <summary> /// Append a class definition (static or otherwise) to this builder. /// </summary> - /// <param name="type">The class type to append.</param> - /// <param name="values">List of values.</param> /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendClassDefinition(Type type, IEnumerable<EmmySharpValue> values) + private EmmySharpBuilder RenderClass(EmmyClass cls) { - AppendDoc(type.EmmyDoc()); - string alias = type.EmmyAlias(); - builder - .AppendLine($"{alias ?? type.Name} = {{}}") + RenderDoc(cls.Doc); + outputBuilder + .AppendLine($"{cls.Name} = {{}}") .AppendLine(); - var staticValues = values.Where(f => f.IsStatic).ToArray(); - - foreach (var staticVal in staticValues) + foreach (var staticVal in cls.IsSingleton ? cls.Statics.Concat(cls.Members) : cls.Statics) { - AppendStaticValue(staticVal, type); + RenderValue(staticVal, cls.Name); } - bool singleton = type.IsDefined(typeof(EmmySingletonAttribute)); - // Ignore instance values and table for static classes - if (!type.IsAbstract || !type.IsSealed) + if (!cls.IsStatic && !cls.IsSingleton) { - AppendDoc(type.EmmyDoc()); - builder.Append($"---@class {alias ?? type.Name}"); + RenderDoc(cls.Doc); + outputBuilder.Append($"---@class {cls.Name}"); - if (type.BaseType != typeof(object) && Attribute.IsDefined(type.BaseType, typeof(MoonSharpUserDataAttribute))) + if (cls.Base != null) { - string baseAlias = type.BaseType.EmmyAlias(); - builder.Append($" : {baseAlias ?? type.BaseType.Name}"); + outputBuilder.Append($" : {cls.Base.Name}"); } - builder.AppendLine(); + outputBuilder.AppendLine(); - foreach (var field in values.Where(f => !f.IsStatic)) + foreach (var field in cls.Members) { - AppendField(field); + if (!(field is EmmyFunction)) + { + RenderField(field); + } } - if (!singleton) + outputBuilder.AppendLine($"local {cls.Name}__inst = {{}}"); + outputBuilder.AppendLine(); + + foreach (var field in cls.Members) { - builder.AppendLine($"{alias ?? type.Name}__inst = {{}}"); - builder.AppendLine(); + if (field is EmmyFunction f) + { + RenderFunction(f, $"{cls.Name}__inst"); + } } } - else if (staticValues.Length != 0) + + return this; + } + + private EmmyFunction LoadMethod(MethodInfo met) + { + return new EmmyFunction { - builder.AppendLine(); - } + Doc = met.EmmyDoc(), + Name = met.EmmyName(camelCase: true), + Parameters = met.GetParameters() + .Select(p => new EmmyValue { Doc = p.EmmyDoc(), Name = p.EmmyName(p.Name), Type = p.GetEmmyType(p.ParameterType, aliases), ParamHasDefaultValue = p.HasDefaultValue }) + .ToArray(), + Return = met.ReturnParameter.GetEmmyType(met.ReturnType, aliases), + }; + } + + public EmmySharpBuilder AppendFunction(MethodInfo met) + { + Add(LoadMethod(met)); return this; } + public EmmySharpBuilder AppendFunction<T>(string name) + => AppendFunction(typeof(T).GetMethod(name)); + /// <summary> /// Append a function with the given documentation. If this function belongs to a type, /// pass it as the member type. /// </summary> - /// <param name="method">The method to append.</param> - /// <param name="memberType">The member type.</param> /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendFunction(MethodInfo method, Type memberType = null) + private EmmySharpBuilder RenderFunction(EmmyFunction function, string baseV = "") { - AppendDoc(method.EmmyDoc()); - - var parameters = method.GetParameters(); + RenderDoc(function.Doc); - foreach (var p in parameters) + foreach (var p in function.Parameters) { - builder.Append($"---@param {p.Name} "); - AppendTypeName(p.ParameterType, p.EmmyChoice()); - builder.AppendLine(); + outputBuilder.Append($"---@param {p.Name}{(p.ParamHasDefaultValue ? "?" : "")} "); + outputBuilder.Append(p.Type); + outputBuilder.Append(' '); + outputBuilder.Append(p.Doc); + outputBuilder.AppendLine(); } - if (method.ReturnType != typeof(void)) + if (function.Return != null) { - builder.Append($"---@return "); - AppendTypeName(method.ReturnType, method.ReturnTypeCustomAttributes.EmmyChoice()); - builder.AppendLine(); + outputBuilder.Append($"---@return "); + outputBuilder.Append(function.Return); + outputBuilder.AppendLine(); } - builder.Append("function "); + outputBuilder.Append("function "); - if (memberType != null) + if (!string.IsNullOrEmpty(baseV)) { - string memberTypeAlias = memberType.EmmyAlias(); - builder.Append(memberTypeAlias ?? memberType.Name); - - bool singleton = memberType.IsDefined(typeof(EmmySingletonAttribute)); - if (!method.IsStatic && !singleton) - { - builder.Append("__inst"); - } - - builder.Append('.'); + outputBuilder.Append(baseV); + outputBuilder.Append('.'); } - string alias = method.EmmyAlias(); - builder.Append(alias ?? method.Name.ToCamelCase()).Append('('); + outputBuilder.Append(function.Name).Append('('); - for (var i = 0; i < parameters.Length; i++) + for (var i = 0; i < function.Parameters.Count; i++) { - var p = parameters[i]; - string paramName = RenameAvoidKeyword(p.Name); + var p = function.Parameters[i]; - builder.Append(paramName); - if (i != parameters.Length - 1) + outputBuilder.Append(p.Name); + if (i != function.Parameters.Count - 1) { - builder.Append(", "); + outputBuilder.Append(", "); } } - builder + outputBuilder .AppendLine(") end") .AppendLine(); @@ -219,147 +689,90 @@ public EmmySharpBuilder AppendFunction(MethodInfo method, Type memberType = null } /// <summary> - /// Appends the type name of the given type. - /// This function may 'error out', in which case an erroneous (but still legal) - /// type will be appended and a warning printed to the console's standard error. + /// Append the given type as if it were exposed by MoonSharp. /// </summary> - /// <param name="ty">Type to append.</param> - /// <param name="options">List of options.</param> + /// <param name="type">The type to append.</param> /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendTypeName(Type ty, string[] options = null) + public EmmySharpBuilder AppendType(Type type) { - if (ty == typeof(short) || ty == typeof(int) || ty == typeof(long) - || ty == typeof(ushort) || ty == typeof(uint) || ty == typeof(ulong)) + EmmyClass BuildClass(Type ty) { - builder.Append("integer"); - } - else if (ty == typeof(float) || ty == typeof(double) || ty == typeof(decimal)) - { - builder.Append("number"); - } - else if (ty == typeof(bool)) - { - builder.Append("boolean"); - } - else if (ty == typeof(string)) - { - if (options != null) + if (ty.IsConstructedGenericType) { - builder - .Append('(') - .Append(string.Join(" | ", options.Select(t => $"'{t}'"))) - .Append(')'); + ty = ty.GetGenericTypeDefinition(); } - else - { - builder.Append("string"); - } - } - else if (ty == typeof(object)) - { - builder.Append("any"); - } - else if (ty.IsArray) - { - AppendTypeName(ty.GetElementType(), options); - builder.Append("[]"); - } - else if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(List<>)) - { - AppendTypeName(ty.GetGenericArguments()[0], options); - builder.Append("[]"); - } - else if (ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - { - builder.Append("table<"); - AppendTypeName(ty.GetGenericArguments()[0], options); - builder.Append(", "); - AppendTypeName(ty.GetGenericArguments()[1], options); - builder.Append('>'); - } - else if (Attribute.IsDefined(ty, typeof(MoonSharpUserDataAttribute))) - { - builder.Append(ty.Name); - } - else if (typeof(Delegate).IsAssignableFrom(ty)) - { - var invoke = ty.GetMethod("Invoke"); - var iparams = invoke.GetParameters(); - builder.Append("fun("); - for (var i = 0; i < iparams.Length; i++) + var cls = new EmmyClass { Name = ty.EmmyName() }; + + if (ty.BaseType != null && ty.BaseType.Visible()) { - var p = iparams[i]; + var baseTy = ty.BaseType; - if (p.ParameterType == ty) + if (baseTy.IsConstructedGenericType) { - Console.Error.WriteLine($"[ERROR]: Cannot generate emmylua for type {ty.FullName} since it is a recursive delegate type, falling back to 'fun(...):any'"); - builder.Append(") : any"); - return this; + // TODO: support real generics + baseTy = baseTy.GetGenericTypeDefinition(); } - builder.Append(p.Name + ":"); - AppendTypeName(p.ParameterType, p.EmmyChoice()); - - if (i != iparams.Length - 1) + if (!classes.TryGetValue(ty.BaseType, out var baseCls)) { - builder.Append(", "); + baseCls = BuildClass(ty.BaseType); } + + cls.Base = baseCls; } - builder.Append(')'); + var members = new List<EmmyValue>(); + var statics = new List<EmmyValue>(); - if (invoke.ReturnType != typeof(void)) + cls.Members = members; + cls.Statics = statics; + + foreach (var val in ty.GetFields() + .Where(t => t.IsPublic) + .Where(t => t.DeclaringType == ty) + .Where(EmmyHelpers.Visible)) { - builder.Append(" : "); - AppendTypeName(invoke.ReturnType, options); + (val.IsStatic ? statics : members).Add(new EmmyValue + { + Doc = val.EmmyDoc(), + Name = val.EmmyName(camelCase: true), + Type = val.GetEmmyType(val.FieldType, aliases), + }); } - } - else - { - Console.Error.WriteLine($"[ERROR]: Cannot generate emmylua for type {ty.FullName}, falling back to type 'any'"); - builder.Append("any"); - } - - return this; - } - /// <summary> - /// Append the given type as if it were exposed by MoonSharp. - /// </summary> - /// <param name="type">The type to append.</param> - /// <returns>The builder instance.</returns> - public EmmySharpBuilder AppendType(Type type) - { - var fields = new List<EmmySharpValue>(); + foreach (var val in ty.GetProperties() + .Where(t => t.GetAccessors().First().IsPublic) + .Where(t => t.DeclaringType == ty) + .Where(EmmyHelpers.Visible)) + { + (val.GetAccessors().First().IsStatic ? statics : members).Add(new EmmyValue + { + Doc = val.EmmyDoc(), + Name = val.EmmyName(camelCase: true), + Type = val.GetEmmyType(val.PropertyType, aliases), + }); + } - foreach (var val in type.GetFields() - .Where(t => t.IsPublic) - .Where(t => t.DeclaringType == type) - .Where(t => !Attribute.IsDefined(t, typeof(MoonSharpHiddenAttribute)))) - { - fields.Add(new EmmySharpValue(val.EmmyDoc(), val.Name, val.FieldType, val.EmmyChoice(), val.IsStatic)); - } + foreach (var met in ty.GetMethods() + .Where(t => t.IsPublic) + .Where(t => !t.IsSpecialName) + .Where(t => t.DeclaringType == ty) + .Where(EmmyHelpers.Visible)) + { + // TODO: handle operators + (met.IsStatic ? statics : members).Add(LoadMethod(met)); + } - foreach (var val in type.GetProperties() - .Where(t => t.GetAccessors().Any(a => a.IsPublic)) - .Where(t => t.DeclaringType == type) - .Where(t => !Attribute.IsDefined(t, typeof(MoonSharpHiddenAttribute)))) - { - fields.Add(new EmmySharpValue(val.EmmyDoc(), val.Name, val.PropertyType, val.EmmyChoice(), val.GetGetMethod().IsStatic)); - } + cls.IsStatic = ty.IsAbstract && ty.IsSealed; + cls.IsSingleton = ty.GetAttrOrNull<EmmySingletonAttribute>() != null; - AppendClassDefinition(type, fields); + Add(ty, cls); - foreach (var met in type.GetMethods() - .Where(t => t.IsPublic) - .Where(t => !t.IsSpecialName) - .Where(t => t.DeclaringType == type) - .Where(t => !Attribute.IsDefined(t, typeof(MoonSharpHiddenAttribute)))) - { - AppendFunction(met, type); + return cls; } + BuildClass(type); return this; } @@ -371,6 +784,19 @@ public EmmySharpBuilder AppendType(Type type) public EmmySharpBuilder AppendType<T>() => AppendType(typeof(T)); + public EmmySharpBuilder AppendAlias(string name, EmmyType type) + { + var alias = EmmyType.Alias(name, type); + aliases[name] = alias; + + foreach (var constituent in alias.Constituents) + { + constituentTypes.Add(constituent); + } + + return this; + } + /// <summary> /// Append all type information from the given assembly, including types not added to MoonSharp, /// which fall under the given group. @@ -381,8 +807,8 @@ public EmmySharpBuilder AppendType<T>() public EmmySharpBuilder AppendGroup(Assembly assembly, string group) { foreach (var ty in assembly.GetTypes() - .Where(t => Attribute.IsDefined(t, typeof(EmmyGroupAttribute))) - .Where(t => ((EmmyGroupAttribute)Attribute.GetCustomAttribute(t, typeof(EmmyGroupAttribute))).GroupName == group)) + .Where(EmmyHelpers.Visible) + .Where(t => t.GetAttrOrNull<EmmyGroupAttribute>()?.GroupName == group)) { AppendType(ty); } @@ -406,7 +832,7 @@ public EmmySharpBuilder AppendGroup(string group) /// <returns>The builder instance.</returns> public EmmySharpBuilder AppendAssembly(Assembly assembly) { - foreach (var ty in assembly.GetTypes().Where(t => Attribute.IsDefined(t, typeof(MoonSharpUserDataAttribute)))) + foreach (var ty in assembly.GetTypes().Where(EmmyHelpers.Visible)) { AppendType(ty); } @@ -436,38 +862,8 @@ public void Build(string filepath) filepath = Path.Combine(filepath, "lib.lua"); File.WriteAllText(filepath, c); - } - private string RenameAvoidKeyword(string name) - { - switch (name) - { - case "and": - case "break": - case "do": - case "else": - case "elseif": - case "end": - case "false": - case "for": - case "function": - case "goto": - case "if": - case "in": - case "local": - case "nil": - case "not": - case "or": - case "repeat": - case "return": - case "then": - case "true": - case "until": - case "while": - return "_" + name; - default: - return name; - } + Debug.Log("Built emmylua to " + filepath); } } } \ No newline at end of file diff --git a/Assets/Scripts/Utility/EmmySharp/EmmyTypeAttribute.cs b/Assets/Scripts/Utility/EmmySharp/EmmyTypeAttribute.cs new file mode 100644 index 00000000..6a5a2490 --- /dev/null +++ b/Assets/Scripts/Utility/EmmySharp/EmmyTypeAttribute.cs @@ -0,0 +1,27 @@ +/// <summary> +/// EmmySharp, created by Dylan Rafael (floofer++) for use by 0thElement. +/// The below classes help to generate EmmyLua workspace files from MoonSharp classes. +/// </summary> + +using System; + +namespace EmmySharp +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue)] + public class EmmyTypeAttribute : Attribute + { + public EmmyTypeAttribute(Type type) + { + Type = type; + } + + public EmmyTypeAttribute(string raw) + { + Raw = raw; + } + + public Type Type { get; } + + public string Raw { get; } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Utility/EmmySharp/EmmyTypeAttribute.cs.meta b/Assets/Scripts/Utility/EmmySharp/EmmyTypeAttribute.cs.meta new file mode 100644 index 00000000..0e5bc1b5 --- /dev/null +++ b/Assets/Scripts/Utility/EmmySharp/EmmyTypeAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0692feb8171682848a465b80d6bef242 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Utility/Extension/CollectionExtension.cs b/Assets/Scripts/Utility/Extension/CollectionExtension.cs index b594cbec..cf30dd6f 100644 --- a/Assets/Scripts/Utility/Extension/CollectionExtension.cs +++ b/Assets/Scripts/Utility/Extension/CollectionExtension.cs @@ -7,6 +7,21 @@ namespace ArcCreate.Utility.Extension { public static class CollectionExtension { + /// <summary> + /// Add all the elements from one list to another without + /// any conversion to IEnumerable. + /// </summary> + /// <param name="list">The list to add to.</param> + /// <param name="other">The source list to take elements from.</param> + /// <typeparam name="T">The type of the element in each list.</typeparam> + public static void FastAddRange<T>(this IList<T> list, IReadOnlyList<T> other) + { + for (int i = 0; i < other.Count; i++) + { + list.Add(other[i]); + } + } + /// <summary> /// Whether or not the index is outside the range of the collection. /// </summary> diff --git a/Assets/Scripts/Utility/TRS.cs b/Assets/Scripts/Utility/TRS.cs new file mode 100644 index 00000000..edac91bc --- /dev/null +++ b/Assets/Scripts/Utility/TRS.cs @@ -0,0 +1,67 @@ +using System; +using UnityEngine; + +namespace ArcCreate.Utility +{ + /// <summary> + /// A simple data structure which represents a TRS transformation, + /// implementing two operations, (+) and (*), to simplify their + /// combination. + /// The main reasoning for this type's existence is to dimplify access + /// to the components of a TRS matrix transformation. + /// </summary> + public struct TRS + { + public TRS(Vector3 position, Quaternion rot, Vector3 scale) + { + Translation = position; + Rotation = rot; + Scale = scale; + } + + public TRS(Matrix4x4 matrix) + { + if (!matrix.ValidTRS()) + { + throw new InvalidOperationException("Cannot create a transform from an invalid TRS matrix!"); + } + + Translation = matrix.GetColumn(3); + Rotation = matrix.rotation; + Scale = matrix.lossyScale; + + // Debug.Log("Scale = " + Scale); + } + + #pragma warning disable + public static TRS identity + #pragma warning restore + => new TRS(Vector3.zero, Quaternion.identity, Vector3.one); + + public Vector3 Translation { get; set; } + + public Quaternion Rotation { get; set; } + + public Vector3 Scale { get; set; } + + public Matrix4x4 Matrix => Matrix4x4.TRS(Translation, Rotation, Scale); + + public static implicit operator Matrix4x4(TRS a) + => a.Matrix; + + public static TRS operator +(TRS a, TRS b) + => new TRS( + a.Translation + b.Translation, + a.Rotation * b.Rotation, + new Vector3(a.Scale.x * b.Scale.x, a.Scale.y * b.Scale.y, a.Scale.z * b.Scale.z)); + + public static TRS operator *(TRS a, TRS b) + => new TRS(a.Matrix * b.Matrix); + + public static TRS TranslateOnly(Vector3 translate) + => new TRS(translate, Quaternion.identity, Vector3.one); + + public static TRS ScaleOnly(Vector3 scale) + => new TRS(Vector3.zero, Quaternion.identity, scale); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Utility/TRS.cs.meta b/Assets/Scripts/Utility/TRS.cs.meta new file mode 100644 index 00000000..c532caa3 --- /dev/null +++ b/Assets/Scripts/Utility/TRS.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 708159425c6c5f24cb36567fe813df00 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/default.arcpkg.meta b/Assets/StreamingAssets/default.arcpkg.meta index fa1ead5f..c85dedf8 100644 --- a/Assets/StreamingAssets/default.arcpkg.meta +++ b/Assets/StreamingAssets/default.arcpkg.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: e973375a25be4344bb963c2bd2e1e236 +guid: 23da70d899e8de4449a1a7f4edd0b55c DefaultImporter: externalObjects: {} userData: diff --git a/Assets/Tests/Scenecontrol/TriggerTest.cs b/Assets/Tests/Scenecontrol/TriggerTest.cs index 6fb15f60..49ad7a44 100644 --- a/Assets/Tests/Scenecontrol/TriggerTest.cs +++ b/Assets/Tests/Scenecontrol/TriggerTest.cs @@ -149,6 +149,7 @@ public override List<object> SerializeProperties(ScenecontrolSerialization seria } } + [SerializationExempt] private class ManualChannel : ValueChannel { public float Value { get; set; }