diff --git a/fluXis.Game/Map/MapInfo.cs b/fluXis.Game/Map/MapInfo.cs index 1e18bef1..a18073bc 100644 --- a/fluXis.Game/Map/MapInfo.cs +++ b/fluXis.Game/Map/MapInfo.cs @@ -38,8 +38,8 @@ public class MapInfo public float AccuracyDifficulty { get; set; } = 8; public float HealthDifficulty { get; set; } = 8; - [JsonIgnore] - public DualMode DualMode => DualMode.Disabled; + [JsonProperty("dual")] + public DualMode DualMode { get; set; } = DualMode.Disabled; [JsonIgnore] public bool IsDual => DualMode > DualMode.Disabled; diff --git a/fluXis.Game/Map/Structures/Bases/IApplicableToPlayfield.cs b/fluXis.Game/Map/Structures/Bases/IApplicableToPlayfield.cs index 28dbc789..b62820bd 100644 --- a/fluXis.Game/Map/Structures/Bases/IApplicableToPlayfield.cs +++ b/fluXis.Game/Map/Structures/Bases/IApplicableToPlayfield.cs @@ -4,5 +4,7 @@ namespace fluXis.Game.Map.Structures.Bases; public interface IApplicableToPlayfield : ITimedObject { + int PlayfieldIndex { get; set; } + void Apply(Playfield playfield); } diff --git a/fluXis.Game/Map/Structures/Events/PlayfieldFadeEvent.cs b/fluXis.Game/Map/Structures/Events/PlayfieldFadeEvent.cs index 7e40d2d2..3346892a 100644 --- a/fluXis.Game/Map/Structures/Events/PlayfieldFadeEvent.cs +++ b/fluXis.Game/Map/Structures/Events/PlayfieldFadeEvent.cs @@ -19,6 +19,9 @@ public class PlayfieldFadeEvent : IMapEvent, IHasDuration, IHasEasing, IApplicab [JsonProperty("ease")] public Easing Easing { get; set; } + [JsonProperty("playfield")] + public int PlayfieldIndex { get; set; } + public void Apply(Playfield playfield) { using (playfield.BeginAbsoluteSequence(Time)) diff --git a/fluXis.Game/Map/Structures/Events/PlayfieldMoveEvent.cs b/fluXis.Game/Map/Structures/Events/PlayfieldMoveEvent.cs index 5935d0d5..dcb5e864 100644 --- a/fluXis.Game/Map/Structures/Events/PlayfieldMoveEvent.cs +++ b/fluXis.Game/Map/Structures/Events/PlayfieldMoveEvent.cs @@ -22,6 +22,9 @@ public class PlayfieldMoveEvent : IMapEvent, IHasDuration, IHasEasing, IApplicab [JsonProperty("ease")] public Easing Easing { get; set; } = Easing.OutQuint; + [JsonProperty("playfield")] + public int PlayfieldIndex { get; set; } + public void Apply(Playfield playfield) { using (playfield.BeginAbsoluteSequence(Time)) diff --git a/fluXis.Game/Map/Structures/Events/PlayfieldRotateEvent.cs b/fluXis.Game/Map/Structures/Events/PlayfieldRotateEvent.cs index 1a7bac8f..da7d63ae 100644 --- a/fluXis.Game/Map/Structures/Events/PlayfieldRotateEvent.cs +++ b/fluXis.Game/Map/Structures/Events/PlayfieldRotateEvent.cs @@ -28,6 +28,9 @@ public class PlayfieldRotateEvent : IMapEvent, IHasDuration, IHasEasing, IApplic [JsonProperty("ease")] public Easing Easing { get; set; } = Easing.OutQuint; + [JsonProperty("playfield")] + public int PlayfieldIndex { get; set; } + public void Apply(Playfield playfield) { using (playfield.BeginAbsoluteSequence(Time)) diff --git a/fluXis.Game/Map/Structures/Events/PlayfieldScaleEvent.cs b/fluXis.Game/Map/Structures/Events/PlayfieldScaleEvent.cs index e6e8c896..7b317149 100644 --- a/fluXis.Game/Map/Structures/Events/PlayfieldScaleEvent.cs +++ b/fluXis.Game/Map/Structures/Events/PlayfieldScaleEvent.cs @@ -23,6 +23,9 @@ public class PlayfieldScaleEvent : IMapEvent, IHasDuration, IHasEasing, IApplica [JsonProperty("ease")] public Easing Easing { get; set; } = Easing.OutQuint; + [JsonProperty("playfield")] + public int PlayfieldIndex { get; set; } + public void Apply(Playfield playfield) { var yScale = ScaleY; diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs b/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs index 40a6710c..ff9a738e 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs @@ -69,7 +69,7 @@ protected override IEnumerable CreateContent() Alpha = Editor.BindableBackgroundDim.Value }, new EditorFlashLayer { InBackground = true }, - new EditorDesignPlayfield(), + new EditorDesignPlayfieldManager(Map.MapInfo.DualMode), new EditorFlashLayer() }) } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfield.cs b/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfield.cs index 5edc9cd9..649f70e7 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfield.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfield.cs @@ -1,5 +1,5 @@ using System.Linq; -using fluXis.Game.Map.Structures.Events; +using fluXis.Game.Map.Structures.Bases; using fluXis.Game.Screens.Edit.Tabs.Shared.Lines; using fluXis.Game.Screens.Gameplay.Ruleset; using fluXis.Game.Skinning; @@ -16,13 +16,21 @@ public partial class EditorDesignPlayfield : CompositeDrawable [Resolved] private EditorMap map { get; set; } + [Resolved] + private LaneSwitchManager laneSwitchManager { get; set; } + [Resolved] private EditorClock clock { get; set; } public FillFlowContainer Receptors { get; private set; } private Drawable hitline; - private LaneSwitchManager laneSwitchManager; + private int index { get; } + + public EditorDesignPlayfield(int index) + { + this.index = index; + } [BackgroundDependencyLoader] private void load(SkinManager skinManager) @@ -33,15 +41,8 @@ private void load(SkinManager skinManager) Origin = Anchor.Centre; AlwaysPresent = true; - laneSwitchManager = new LaneSwitchManager(map.MapEvents.LaneSwitchEvents, map.RealmMap.KeyCount) - { - KeepTransforms = true, - Clock = clock - }; - InternalChildren = new[] { - laneSwitchManager, new Stage(), new EditorTimingLines(), Receptors = new FillFlowContainer @@ -64,34 +65,15 @@ protected override void LoadComplete() { base.LoadComplete(); - map.LaneSwitchEventAdded += reloadLaneSwitches; - map.LaneSwitchEventUpdated += reloadLaneSwitches; - map.LaneSwitchEventRemoved += reloadLaneSwitches; - reload(); } - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - map.LaneSwitchEventAdded -= reloadLaneSwitches; - map.LaneSwitchEventUpdated -= reloadLaneSwitches; - map.LaneSwitchEventRemoved -= reloadLaneSwitches; - } - private void reload() { - reloadLaneSwitches(null); Receptors.Clear(); Receptors.ChildrenEnumerable = Enumerable.Range(0, map.RealmMap.KeyCount).Select(i => new EditorDesignReceptor(i, laneSwitchManager)); } - private void reloadLaneSwitches(LaneSwitchEvent _) - { - laneSwitchManager.Rebuild(map.MapEvents.LaneSwitchEvents, map.RealmMap.KeyCount); - } - protected override void Update() { base.Update(); @@ -104,9 +86,17 @@ protected override void Update() updateAlpha(); } + private bool applies(IApplicableToPlayfield ev) + { + if (ev.PlayfieldIndex == 0) + return true; + + return ev.PlayfieldIndex == index + 1; + } + private void updateRotation() { - var current = map.MapEvents.PlayfieldRotateEvents.LastOrDefault(e => e.Time <= clock.CurrentTime); + var current = map.MapEvents.PlayfieldRotateEvents.Where(applies).LastOrDefault(e => e.Time <= clock.CurrentTime); if (current == null) { @@ -123,7 +113,7 @@ private void updateRotation() return; } - var previous = map.MapEvents.PlayfieldRotateEvents.LastOrDefault(e => e.Time < current.Time); + var previous = map.MapEvents.PlayfieldRotateEvents.Where(applies).LastOrDefault(e => e.Time < current.Time); var start = previous?.Roll ?? 0; if (progress < 0) @@ -137,7 +127,7 @@ private void updateRotation() private void updateAlpha() { - var current = map.MapEvents.PlayfieldFadeEvents.LastOrDefault(e => e.Time <= clock.CurrentTime); + var current = map.MapEvents.PlayfieldFadeEvents.Where(applies).LastOrDefault(e => e.Time <= clock.CurrentTime); if (current == null) { @@ -154,7 +144,7 @@ private void updateAlpha() return; } - var previous = map.MapEvents.PlayfieldFadeEvents.LastOrDefault(e => e.Time < current.Time); + var previous = map.MapEvents.PlayfieldFadeEvents.Where(applies).LastOrDefault(e => e.Time < current.Time); var start = previous?.Alpha ?? 1; if (progress < 0) @@ -168,7 +158,7 @@ private void updateAlpha() private void updateScale() { - var curScale = map.MapEvents.PlayfieldScaleEvents.LastOrDefault(e => e.Time <= clock.CurrentTime); + var curScale = map.MapEvents.PlayfieldScaleEvents.Where(applies).LastOrDefault(e => e.Time <= clock.CurrentTime); if (curScale == null) { @@ -185,7 +175,7 @@ private void updateScale() return; } - var prevScale = map.MapEvents.PlayfieldScaleEvents.LastOrDefault(e => e.Time < curScale.Time); + var prevScale = map.MapEvents.PlayfieldScaleEvents.Where(applies).LastOrDefault(e => e.Time < curScale.Time); var prev = Vector2.One; if (prevScale != null) @@ -202,7 +192,7 @@ private void updateScale() private void updatePosition() { - var curMove = map.MapEvents.PlayfieldMoveEvents.LastOrDefault(e => e.Time <= clock.CurrentTime); + var curMove = map.MapEvents.PlayfieldMoveEvents.Where(applies).LastOrDefault(e => e.Time <= clock.CurrentTime); if (curMove == null) { @@ -219,7 +209,7 @@ private void updatePosition() return; } - var prevMove = map.MapEvents.PlayfieldMoveEvents.LastOrDefault(e => e.Time < curMove.Time); + var prevMove = map.MapEvents.PlayfieldMoveEvents.Where(applies).LastOrDefault(e => e.Time < curMove.Time); var prev = Vector2.One; if (prevMove != null) diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfieldManager.cs b/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfieldManager.cs new file mode 100644 index 00000000..22156ad2 --- /dev/null +++ b/fluXis.Game/Screens/Edit/Tabs/Design/Playfield/EditorDesignPlayfieldManager.cs @@ -0,0 +1,83 @@ +using System.Linq; +using fluXis.Game.Map.Structures.Events; +using fluXis.Game.Screens.Gameplay.Ruleset; +using fluXis.Shared.Components.Maps; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace fluXis.Game.Screens.Edit.Tabs.Design.Playfield; + +public partial class EditorDesignPlayfieldManager : CompositeDrawable +{ + [Resolved] + private EditorMap map { get; set; } + + [Resolved] + private EditorClock clock { get; set; } + + private LaneSwitchManager laneSwitchManager; + private DependencyContainer dependencies; + + public int Count { get; } + + public EditorDesignPlayfieldManager(DualMode mode) + { + Count = mode > DualMode.Disabled ? 2 : 1; + } + + [BackgroundDependencyLoader] + private void load() + { + RelativeSizeAxes = Axes.Both; + + dependencies.CacheAs(laneSwitchManager = new LaneSwitchManager(map.MapEvents.LaneSwitchEvents, map.RealmMap.KeyCount) + { + KeepTransforms = true, + Clock = clock + }); + + InternalChildren = new Drawable[] + { + laneSwitchManager, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + Enumerable.Range(0, Count) + .Select(i => new EditorDesignPlayfield(i)) + .ToArray() + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + map.LaneSwitchEventAdded += reloadLaneSwitches; + map.LaneSwitchEventUpdated += reloadLaneSwitches; + map.LaneSwitchEventRemoved += reloadLaneSwitches; + + reloadLaneSwitches(null); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + map.LaneSwitchEventAdded -= reloadLaneSwitches; + map.LaneSwitchEventUpdated -= reloadLaneSwitches; + map.LaneSwitchEventRemoved -= reloadLaneSwitches; + } + + private void reloadLaneSwitches(LaneSwitchEvent _) + { + laneSwitchManager.Rebuild(map.MapEvents.LaneSwitchEvents, map.RealmMap.KeyCount); + } + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); +} diff --git a/fluXis.Game/Screens/Gameplay/Ruleset/HitObjects/HitObjectManager.cs b/fluXis.Game/Screens/Gameplay/Ruleset/HitObjects/HitObjectManager.cs index 2ee14809..7ec07868 100644 --- a/fluXis.Game/Screens/Gameplay/Ruleset/HitObjects/HitObjectManager.cs +++ b/fluXis.Game/Screens/Gameplay/Ruleset/HitObjects/HitObjectManager.cs @@ -76,6 +76,11 @@ protected override void LoadComplete() input.OnPress += key => { var lane = input.Keys.IndexOf(key) + 1; + lane -= KeyCount * playfield.Index; + + if (lane > KeyCount || lane <= 0) + return; + var hit = this[lane - 1].NextUp; if (hit == null) diff --git a/fluXis.Shared/Components/Maps/DualMode.cs b/fluXis.Shared/Components/Maps/DualMode.cs index bad30211..56feb03d 100644 --- a/fluXis.Shared/Components/Maps/DualMode.cs +++ b/fluXis.Shared/Components/Maps/DualMode.cs @@ -3,5 +3,5 @@ public enum DualMode { Disabled, - Enabled + Mirrored }