From 74f1a9622f61d112fdc7b89dc9dcdc678d7b6c1b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 28 Oct 2016 19:55:48 +0900 Subject: [PATCH] Add initial game-wide beatmap flow. --- osu.Game/Beatmaps/Drawable/BeatmapGroup.cs | 23 ++++--- osu.Game/Beatmaps/WorkingBeatmap.cs | 15 ++-- osu.Game/Database/BeatmapDatabase.cs | 4 +- osu.Game/Database/BeatmapInfo.cs | 7 +- osu.Game/GameModes/Menu/Intro.cs | 2 + osu.Game/GameModes/OsuGameMode.cs | 63 ++++++++++++++++- osu.Game/GameModes/Play/PlaySongSelect.cs | 80 +++++++++++++++++++--- osu.Game/GameModes/Play/Player.cs | 35 +++++----- osu.Game/OsuGame.cs | 5 +- osu.Game/OsuGameBase.cs | 14 +++- 10 files changed, 197 insertions(+), 51 deletions(-) diff --git a/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs b/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs index 57ca1190e3..3b8c458110 100644 --- a/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs +++ b/osu.Game/Beatmaps/Drawable/BeatmapGroup.cs @@ -2,6 +2,7 @@ //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; using System.Linq; using osu.Framework; using osu.Framework.Graphics; @@ -27,6 +28,8 @@ namespace osu.Game.Beatmaps.Drawable private BeatmapGroupState state; + public IEnumerable BeatmapPanels; + public BeatmapGroupState State { get { return state; } @@ -62,6 +65,16 @@ namespace osu.Game.Beatmaps.Drawable AutoSizeAxes = Axes.Y; RelativeSizeAxes = Axes.X; + BeatmapPanels = beatmapSet.Beatmaps.Select(b => + new BeatmapPanel(this.beatmapSet, b) + { + GainedSelection = panelGainedSelection, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.X, + }); + + Children = new[] { new FlowContainer @@ -87,15 +100,7 @@ namespace osu.Game.Beatmaps.Drawable Spacing = new Vector2(0, 5), Direction = FlowDirection.VerticalOnly, Alpha = 0, - Children = this.beatmapSet.Beatmaps.Select(b => - new BeatmapPanel(this.beatmapSet, b) - { - GainedSelection = panelGainedSelection, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.X, - } - ) + Children = BeatmapPanels } } } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 5ea8faf9c7..a805454441 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -17,16 +17,15 @@ namespace osu.Game.Beatmaps { get { - if (track == null) + if (track != null) return track; + + try { - try - { - var trackData = Reader.ReadFile(Beatmap.Metadata.AudioFile); - if (trackData != null) - track = new AudioTrackBass(trackData); - } - catch { } + var trackData = Reader.ReadFile(Beatmap.Metadata.AudioFile); + if (trackData != null) + track = new AudioTrackBass(trackData); } + catch { } return track; } diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs index 4c98d66757..7f4bd32f70 100644 --- a/osu.Game/Database/BeatmapDatabase.cs +++ b/osu.Game/Database/BeatmapDatabase.cs @@ -136,7 +136,7 @@ namespace osu.Game.Database return Query().Where(s => s.BeatmapSetID == id).FirstOrDefault(); } - public WorkingBeatmap GetBeatmapData(BeatmapInfo beatmapInfo) + public WorkingBeatmap GetWorkingBeatmap(BeatmapInfo beatmapInfo) { var beatmapSet = Query().Where(s => s.BeatmapSetID == beatmapInfo.BeatmapSetID).FirstOrDefault(); if (beatmapSet == null) @@ -150,7 +150,7 @@ namespace osu.Game.Database public Beatmap GetBeatmap(BeatmapInfo beatmapInfo) { - using (WorkingBeatmap data = GetBeatmapData(beatmapInfo)) + using (WorkingBeatmap data = GetWorkingBeatmap(beatmapInfo)) return data.Beatmap; } diff --git a/osu.Game/Database/BeatmapInfo.cs b/osu.Game/Database/BeatmapInfo.cs index 5b1d0c323c..4d18976ef0 100644 --- a/osu.Game/Database/BeatmapInfo.cs +++ b/osu.Game/Database/BeatmapInfo.cs @@ -7,7 +7,7 @@ using SQLiteNetExtensions.Attributes; namespace osu.Game.Database { - public class BeatmapInfo + public class BeatmapInfo : IEquatable { [PrimaryKey] public int BeatmapID { get; set; } @@ -64,5 +64,10 @@ namespace osu.Game.Database // Metadata public string Version { get; set; } + + public bool Equals(BeatmapInfo other) + { + return BeatmapID == other?.BeatmapID; + } } } \ No newline at end of file diff --git a/osu.Game/GameModes/Menu/Intro.cs b/osu.Game/GameModes/Menu/Intro.cs index f0bba5bddb..2973f83b6b 100644 --- a/osu.Game/GameModes/Menu/Intro.cs +++ b/osu.Game/GameModes/Menu/Intro.cs @@ -10,6 +10,8 @@ using osu.Framework.Graphics.Transformations; using osu.Game.GameModes.Backgrounds; using OpenTK.Graphics; using osu.Framework; +using osu.Framework.Configuration; +using osu.Game.Beatmaps; namespace osu.Game.GameModes.Menu { diff --git a/osu.Game/GameModes/OsuGameMode.cs b/osu.Game/GameModes/OsuGameMode.cs index b0928d8214..d8b73f5f07 100644 --- a/osu.Game/GameModes/OsuGameMode.cs +++ b/osu.Game/GameModes/OsuGameMode.cs @@ -3,17 +3,20 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; +using osu.Framework.Configuration; using osu.Framework.GameModes; using osu.Framework.Graphics.Containers; +using osu.Game.Beatmaps; using osu.Game.Graphics.Background; using osu.Game.Graphics.Containers; namespace osu.Game.GameModes { - public class OsuGameMode : GameMode + public abstract class OsuGameMode : GameMode { internal BackgroundMode Background { get; private set; } @@ -23,6 +26,64 @@ namespace osu.Game.GameModes /// protected virtual BackgroundMode CreateBackground() => null; + private bool boundToBeatmap; + private Bindable beatmap; + + public WorkingBeatmap Beatmap + { + get + { + bindBeatmap(); + return beatmap.Value; + } + set + { + bindBeatmap(); + beatmap.Value = value; + } + } + + private void bindBeatmap() + { + if (beatmap == null) + beatmap = new Bindable(); + + if (!boundToBeatmap) + { + beatmap.ValueChanged += beatmap_ValueChanged; + boundToBeatmap = true; + } + } + + protected override void Dispose(bool isDisposing) + { + if (boundToBeatmap) + beatmap.ValueChanged -= beatmap_ValueChanged; + + base.Dispose(isDisposing); + } + + private void beatmap_ValueChanged(object sender, EventArgs e) + { + OnBeatmapChanged(beatmap.Value); + } + + public override bool Push(GameMode mode) + { + OsuGameMode nextOsu = mode as OsuGameMode; + if (nextOsu != null) + { + nextOsu.beatmap = beatmap; + } + + return base.Push(mode); + } + + protected virtual void OnBeatmapChanged(WorkingBeatmap beatmap) + { + + } + protected override void OnEntering(GameMode last) { OsuGameMode lastOsu = last as OsuGameMode; diff --git a/osu.Game/GameModes/Play/PlaySongSelect.cs b/osu.Game/GameModes/Play/PlaySongSelect.cs index b7c107ca98..9e2302f25a 100644 --- a/osu.Game/GameModes/Play/PlaySongSelect.cs +++ b/osu.Game/GameModes/Play/PlaySongSelect.cs @@ -16,8 +16,11 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Graphics.UserInterface; using System.Threading.Tasks; +using osu.Framework.Audio.Track; using osu.Game.Beatmaps.Drawable; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Game.Beatmaps; +using osu.Framework.GameModes; namespace osu.Game.GameModes.Play { @@ -26,10 +29,12 @@ namespace osu.Game.GameModes.Play private Bindable playMode; private BeatmapDatabase database; private BeatmapGroup selectedBeatmapGroup; + private BeatmapInfo selectedBeatmapInfo; // TODO: use currently selected track as bg protected override BackgroundMode CreateBackground() => new BackgroundModeCustom(@"Backgrounds/bg4"); private ScrollContainer scrollContainer; - private FlowContainer setList; + private FlowContainer beatmapSetFlow; + private TrackManager trackManager; /// Optionally provide a database to use instead of the OsuGame one. public PlaySongSelect(BeatmapDatabase database = null) @@ -73,7 +78,7 @@ namespace osu.Game.GameModes.Play Origin = Anchor.CentreRight, Children = new Drawable[] { - setList = new FlowContainer + beatmapSetFlow = new FlowContainer { Padding = new MarginPadding { Left = 25, Top = 25, Bottom = 25 + bottomToolHeight }, RelativeSizeAxes = Axes.X, @@ -123,7 +128,7 @@ namespace osu.Game.GameModes.Play if (osuGame != null) { playMode = osuGame.PlayMode; - playMode.ValueChanged += PlayMode_ValueChanged; + playMode.ValueChanged += playMode_ValueChanged; // Temporary: scrollContainer.Padding = new MarginPadding { Top = osuGame.Toolbar.Height }; } @@ -133,22 +138,68 @@ namespace osu.Game.GameModes.Play database.BeatmapSetAdded += s => Schedule(() => addBeatmapSet(s)); + trackManager = game.Audio.Track; + Task.Factory.StartNew(addBeatmapSets); } + protected override void OnEntering(GameMode last) + { + base.OnEntering(last); + ensurePlayingSelected(); + } + + protected override void OnResuming(GameMode last) + { + ensurePlayingSelected(); + + base.OnResuming(last); + } + protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); if (playMode != null) - playMode.ValueChanged -= PlayMode_ValueChanged; + playMode.ValueChanged -= playMode_ValueChanged; } - private void PlayMode_ValueChanged(object sender, EventArgs e) + private void playMode_ValueChanged(object sender, EventArgs e) { } - private void selectBeatmap(BeatmapGroup group, BeatmapInfo beatmap) + protected override void OnBeatmapChanged(WorkingBeatmap beatmap) { + base.OnBeatmapChanged(beatmap); + selectBeatmap(beatmap.Beatmap.BeatmapInfo); + } + + private void selectBeatmap(BeatmapInfo beatmap) + { + if (beatmap.Equals(selectedBeatmapInfo)) + return; + + beatmapSetFlow.Children.Cast().First(b => + { + var panel = b.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap)); + panel?.TriggerClick(); + return panel != null; + }); + } + + /// + /// selection has been changed as the result of interaction with the carousel. + /// + private void selectionChanged(BeatmapGroup group, BeatmapInfo beatmap) + { + selectedBeatmapInfo = beatmap; + + if (!beatmap.Equals(Beatmap?.Beatmap?.BeatmapInfo)) + { + Beatmap = database.GetWorkingBeatmap(beatmap); + } + + ensurePlayingSelected(); + if (selectedBeatmapGroup == group) return; @@ -158,6 +209,17 @@ namespace osu.Game.GameModes.Play selectedBeatmapGroup = group; } + private void ensurePlayingSelected() + { + var track = Beatmap?.Track; + + if (track != null) + { + trackManager.SetExclusive(track); + track.Start(); + } + } + private void addBeatmapSet(BeatmapSetInfo beatmapSet) { beatmapSet = database.GetWithChildren(beatmapSet.BeatmapSetID); @@ -165,9 +227,9 @@ namespace osu.Game.GameModes.Play beatmapSet.Beatmaps = beatmapSet.Beatmaps.OrderBy(b => b.BaseDifficulty.OverallDifficulty).ToList(); Schedule(() => { - var group = new BeatmapGroup(beatmapSet) { SelectionChanged = selectBeatmap }; - setList.Add(group); - if (setList.Children.Count() == 1) + var group = new BeatmapGroup(beatmapSet) { SelectionChanged = selectionChanged }; + beatmapSetFlow.Add(group); + if (beatmapSetFlow.Children.Count() == 1) group.State = BeatmapGroupState.Expanded; }); } diff --git a/osu.Game/GameModes/Play/Player.cs b/osu.Game/GameModes/Play/Player.cs index 2302c026f3..e5aceeb5d8 100644 --- a/osu.Game/GameModes/Play/Player.cs +++ b/osu.Game/GameModes/Play/Player.cs @@ -22,7 +22,6 @@ namespace osu.Game.GameModes.Play protected override BackgroundMode CreateBackground() => new BackgroundModeCustom(@"Backgrounds/bg4"); public BeatmapInfo BeatmapInfo; - public WorkingBeatmap Beatmap; public PlayMode PreferredPlayMode; @@ -31,16 +30,13 @@ namespace osu.Game.GameModes.Play private InterpolatingFramedClock playerClock; private IAdjustableClock sourceClock; - protected override void Dispose(bool isDisposing) - { - Beatmap?.Dispose(); - base.Dispose(isDisposing); - } - protected override bool OnExiting(GameMode next) { - //eagerly dispose as the finalizer runs too late right now. - Beatmap?.Dispose(); + if (next == null) + { + //eagerly dispose as the finalizer runs too late right now. + Beatmap?.Dispose(); + } return base.OnExiting(next); } @@ -52,7 +48,7 @@ namespace osu.Game.GameModes.Play try { if (Beatmap == null) - Beatmap = ((OsuGame)game).Beatmaps.GetBeatmapData(BeatmapInfo); + Beatmap = ((OsuGame)game).Beatmaps.GetWorkingBeatmap(BeatmapInfo); } catch { @@ -69,27 +65,28 @@ namespace osu.Game.GameModes.Play sourceClock = track; } - sourceClock = (IAdjustableClock)Beatmap.Track ?? new StopwatchClock(); + sourceClock = (IAdjustableClock)track ?? new StopwatchClock(); playerClock = new InterpolatingFramedClock(sourceClock); Schedule(() => { + sourceClock.Reset(); sourceClock.Start(); }); HitRenderer hitRenderer; ScoreOverlay scoreOverlay; - if (Beatmap.Beatmap.BeatmapInfo?.Mode > PlayMode.Osu) + var beatmap = Beatmap.Beatmap; + + if (beatmap.BeatmapInfo?.Mode > PlayMode.Osu) { //we only support osu! mode for now because the hitobject parsing is crappy and needs a refactor. Exit(); return; } - PlayMode usablePlayMode = Beatmap.Beatmap.BeatmapInfo?.Mode > PlayMode.Osu ? Beatmap.Beatmap.BeatmapInfo.Mode : PreferredPlayMode; - - + PlayMode usablePlayMode = beatmap.BeatmapInfo?.Mode > PlayMode.Osu ? beatmap.BeatmapInfo.Mode : PreferredPlayMode; switch (usablePlayMode) { @@ -98,7 +95,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new OsuHitRenderer { - Objects = Beatmap.Beatmap.HitObjects, + Objects = beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -108,7 +105,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new TaikoHitRenderer { - Objects = Beatmap.Beatmap.HitObjects, + Objects = beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -118,7 +115,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new CatchHitRenderer { - Objects = Beatmap.Beatmap.HitObjects, + Objects = beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -128,7 +125,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new ManiaHitRenderer { - Objects = Beatmap.Beatmap.HitObjects, + Objects = beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 549e79b800..2515ace38e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -70,7 +70,10 @@ namespace osu.Game RelativeSizeAxes = Axes.Both, ActivateRequested = delegate { volume.Show(); } }, - intro = new Intro(), + intro = new Intro + { + Beatmap = Beatmap + }, Toolbar = new Toolbar { OnHome = delegate { MainMenu?.MakeCurrent(); }, diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 4df5683493..bfa07d72c8 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -1,10 +1,13 @@ -using osu.Framework; +using System; +using osu.Framework; +using osu.Framework.Configuration; using osu.Framework.GameModes; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Textures; using osu.Framework.IO.Stores; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.IO; using osu.Game.Configuration; using osu.Game.Database; @@ -32,6 +35,8 @@ namespace osu.Game public CursorContainer Cursor; + public readonly Bindable Beatmap = new Bindable(); + public OsuGameBase() { AddInternal(ratioContainer = new RatioAdjust()); @@ -41,6 +46,13 @@ namespace osu.Game Options = new Options(), Cursor = new OsuCursorContainer() }; + + Beatmap.ValueChanged += Beatmap_ValueChanged; + } + + private void Beatmap_ValueChanged(object sender, EventArgs e) + { + throw new NotImplementedException(); } public override void Load(BaseGame game)