// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. #nullable disable using System; using System.Collections.Generic; using osu.Game.Beatmaps; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; namespace osu.Game.Rulesets.Mania.Replays { public class ManiaReplayFrame : ReplayFrame, IConvertibleReplayFrame { public List Actions = new List(); public ManiaReplayFrame() { } public ManiaReplayFrame(double time, params ManiaAction[] actions) : base(time) { Actions.AddRange(actions); } public void FromLegacy(LegacyReplayFrame legacyFrame, IBeatmap beatmap, ReplayFrame lastFrame = null) { var maniaBeatmap = (ManiaBeatmap)beatmap; var normalAction = ManiaAction.Key1; var specialAction = ManiaAction.Special1; int activeColumns = (int)(legacyFrame.MouseX ?? 0); int counter = 0; while (activeColumns > 0) { bool isSpecial = isColumnAtIndexSpecial(maniaBeatmap, counter); if ((activeColumns & 1) > 0) Actions.Add(isSpecial ? specialAction : normalAction); if (isSpecial) specialAction++; else normalAction++; counter++; activeColumns >>= 1; } } public LegacyReplayFrame ToLegacy(IBeatmap beatmap) { var maniaBeatmap = (ManiaBeatmap)beatmap; int keys = 0; foreach (var action in Actions) { switch (action) { case ManiaAction.Special1: keys |= 1 << getSpecialColumnIndex(maniaBeatmap, 0); break; case ManiaAction.Special2: keys |= 1 << getSpecialColumnIndex(maniaBeatmap, 1); break; default: // the index in lazer, which doesn't include special keys. int nonSpecialKeyIndex = action - ManiaAction.Key1; // the index inclusive of special keys. int overallIndex = 0; // iterate to find the index including special keys. for (; overallIndex < maniaBeatmap.TotalColumns; overallIndex++) { // skip over special columns. if (isColumnAtIndexSpecial(maniaBeatmap, overallIndex)) continue; // found a non-special column to use. if (nonSpecialKeyIndex == 0) break; // found a non-special column but not ours. nonSpecialKeyIndex--; } keys |= 1 << overallIndex; break; } } return new LegacyReplayFrame(Time, keys, null, ReplayButtonState.None); } /// /// Find the overall index (across all stages) for a specified special key. /// /// The beatmap. /// The special key offset (0 is S1). /// The overall index for the special column. private int getSpecialColumnIndex(ManiaBeatmap maniaBeatmap, int specialOffset) { for (int i = 0; i < maniaBeatmap.TotalColumns; i++) { if (isColumnAtIndexSpecial(maniaBeatmap, i)) { if (specialOffset == 0) return i; specialOffset--; } } throw new ArgumentException("Special key index is too high.", nameof(specialOffset)); } /// /// Check whether the column at an overall index (across all stages) is a special column. /// /// The beatmap. /// The overall index to check. private bool isColumnAtIndexSpecial(ManiaBeatmap beatmap, int index) { foreach (var stage in beatmap.Stages) { if (index >= stage.Columns) { index -= stage.Columns; continue; } return stage.IsSpecialColumn(index); } throw new ArgumentException("Column index is too high.", nameof(index)); } } }