diff --git a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs index 69b56ef17d..90d45fe7eb 100644 --- a/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs +++ b/osu.Desktop.VisualTests/Tests/TestCasePlayer.cs @@ -46,10 +46,11 @@ namespace osu.Desktop.VisualTests.Tests Add(new Player() { - Beatmap = new Beatmap - { - HitObjects = objects - } + Beatmap = new WorkingBeatmap( + new Beatmap + { + HitObjects = objects + }) }); } diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs new file mode 100644 index 0000000000..fbf3b8f1e9 --- /dev/null +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -0,0 +1,62 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Audio.Track; +using osu.Game.Beatmaps.IO; + +namespace osu.Game.Beatmaps +{ + public class WorkingBeatmap : IDisposable + { + public readonly ArchiveReader Reader; + public readonly Beatmap Beatmap; + + private AudioTrack track; + public AudioTrack Track + { + get + { + if (track == null) + { + var trackData = Reader.ReadFile(Beatmap.Metadata.AudioFile); + if (trackData != null) + track = new AudioTrackBass(trackData); + } + + return track; + } + set { track = value; } + } + + public WorkingBeatmap(Beatmap beatmap, ArchiveReader reader = null) + { + Beatmap = beatmap; + Reader = reader; + } + + private bool isDisposed; + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + track?.Dispose(); + Reader?.Dispose(); + + isDisposed = true; + } + } + + ~WorkingBeatmap() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/osu.Game/Database/BeatmapDatabase.cs b/osu.Game/Database/BeatmapDatabase.cs index 1b55b0eeaf..4c98d66757 100644 --- a/osu.Game/Database/BeatmapDatabase.cs +++ b/osu.Game/Database/BeatmapDatabase.cs @@ -130,43 +130,46 @@ namespace osu.Game.Database { return ArchiveReader.GetReader(storage, beatmapSet.Path); } - + public BeatmapSetInfo GetBeatmapSet(int id) { return Query().Where(s => s.BeatmapSetID == id).FirstOrDefault(); } - + + public WorkingBeatmap GetBeatmapData(BeatmapInfo beatmapInfo) + { + var beatmapSet = Query().Where(s => s.BeatmapSetID == beatmapInfo.BeatmapSetID).FirstOrDefault(); + if (beatmapSet == null) + throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetID} is not in the local database."); + + var reader = GetReader(beatmapSet); + + using (var stream = new StreamReader(reader.ReadFile(beatmapInfo.Path))) + return new WorkingBeatmap(BeatmapDecoder.GetDecoder(stream)?.Decode(stream), reader); + } + public Beatmap GetBeatmap(BeatmapInfo beatmapInfo) { - var beatmapSet = Query() - .Where(s => s.BeatmapSetID == beatmapInfo.BeatmapSetID).FirstOrDefault(); - if (beatmapSet == null) - throw new InvalidOperationException( - $@"Beatmap set {beatmapInfo.BeatmapSetID} is not in the local database."); - using (var reader = GetReader(beatmapSet)) - using (var stream = new StreamReader(reader.ReadFile(beatmapInfo.Path))) - { - var decoder = BeatmapDecoder.GetDecoder(stream); - return decoder.Decode(stream); - } + using (WorkingBeatmap data = GetBeatmapData(beatmapInfo)) + return data.Beatmap; } - + public TableQuery Query() where T : class { return connection.Table(); } - + public T GetWithChildren(object id) where T : class { return connection.GetWithChildren(id); } - + public List GetAllWithChildren(Expression> filter = null, bool recursive = true) where T : class { return connection.GetAllWithChildren(filter, recursive); } - + public T GetChildren(T item, bool recursive = true) { if (item == null) return default(T); diff --git a/osu.Game/GameModes/Play/Player.cs b/osu.Game/GameModes/Play/Player.cs index 4e18f06f5b..2f948201ad 100644 --- a/osu.Game/GameModes/Play/Player.cs +++ b/osu.Game/GameModes/Play/Player.cs @@ -1,7 +1,6 @@ //Copyright (c) 2007-2016 ppy Pty Ltd . //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Collections.Generic; using osu.Framework.Graphics; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Objects; @@ -12,6 +11,9 @@ using osu.Game.GameModes.Play.Osu; using osu.Game.GameModes.Play.Taiko; using osu.Framework; using osu.Game.Database; +using osu.Framework.Timing; +using osu.Framework.GameModes; +using osu.Framework.Audio.Track; namespace osu.Game.GameModes.Play { @@ -20,10 +22,29 @@ namespace osu.Game.GameModes.Play protected override BackgroundMode CreateBackground() => new BackgroundModeCustom(@"Backgrounds/bg4"); public BeatmapInfo BeatmapInfo; - public Beatmap Beatmap; + public WorkingBeatmap Beatmap; public PlayMode PlayMode; + protected override IFrameBasedClock Clock => playerClock; + + 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(); + + return base.OnExiting(next); + } + public override void Load(BaseGame game) { base.Load(game); @@ -31,7 +52,7 @@ namespace osu.Game.GameModes.Play try { if (Beatmap == null) - Beatmap = ((OsuGame)game).Beatmaps.GetBeatmap(BeatmapInfo); + Beatmap = ((OsuGame)game).Beatmaps.GetBeatmapData(BeatmapInfo); } catch { @@ -40,6 +61,22 @@ namespace osu.Game.GameModes.Play return; } + AudioTrack track = Beatmap.Track; + + if (track != null) + { + game.Audio.Track.SetExclusive(track); + sourceClock = track; + } + + sourceClock = (IAdjustableClock)Beatmap.Track ?? new StopwatchClock(); + playerClock = new InterpolatingFramedClock(sourceClock); + + Schedule(() => + { + sourceClock.Start(); + }); + HitRenderer hitRenderer; ScoreOverlay scoreOverlay; @@ -50,7 +87,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new OsuHitRenderer { - Objects = Beatmap.HitObjects, + Objects = Beatmap.Beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -60,7 +97,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new TaikoHitRenderer { - Objects = Beatmap.HitObjects, + Objects = Beatmap.Beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -70,7 +107,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new CatchHitRenderer { - Objects = Beatmap.HitObjects, + Objects = Beatmap.Beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -80,7 +117,7 @@ namespace osu.Game.GameModes.Play hitRenderer = new ManiaHitRenderer { - Objects = Beatmap.HitObjects, + Objects = Beatmap.Beatmap.HitObjects, Anchor = Anchor.Centre, Origin = Anchor.Centre }; @@ -96,5 +133,11 @@ namespace osu.Game.GameModes.Play scoreOverlay, }; } + + protected override void Update() + { + base.Update(); + playerClock.ProcessFrame(); + } } } \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f044ef9a6e..82fb8f7292 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -64,6 +64,7 @@ +