Skip to content

Commit

Permalink
Access beatmap store via abstract base class
Browse files Browse the repository at this point in the history
The intention here is to make things more testable going forward.
Specifically, to remove the "back-door" entrance into `BeatmapCarousel`
where `BeatmapSets` can be set by tests and bypas/block realm retrieval.
  • Loading branch information
peppy committed Dec 11, 2024
1 parent 5b78331 commit 06d5cf9
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ public partial class TestSceneUserDimBackgrounds : ScreenTestScene
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
DetachedBeatmapStore detachedBeatmapStore;
BeatmapStore beatmapStore;

Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(new OsuConfigManager(LocalStorage));
Dependencies.Cache(detachedBeatmapStore = new DetachedBeatmapStore());
Dependencies.Cache(beatmapStore = new RealmDetachedBeatmapStore());
Dependencies.Cache(Realm);

manager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();

Add(detachedBeatmapStore);
Add(beatmapStore);

Beatmap.SetDefault();
}
Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ public abstract partial class QueueModeTestScene : ScreenTestScene
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
DetachedBeatmapStore detachedBeatmapStore;
BeatmapStore beatmapStore;

Dependencies.Cache(new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(detachedBeatmapStore = new DetachedBeatmapStore());
Dependencies.Cache(beatmapStore = new RealmDetachedBeatmapStore());
Dependencies.Cache(Realm);

Add(detachedBeatmapStore);
Add(beatmapStore);
}

public override void SetUpSteps()
Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ public partial class TestSceneMultiplayer : ScreenTestScene
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
DetachedBeatmapStore detachedBeatmapStore;
BeatmapStore beatmapStore;

Dependencies.Cache(new RealmRulesetStore(Realm));
Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(detachedBeatmapStore = new DetachedBeatmapStore());
Dependencies.Cache(beatmapStore = new RealmDetachedBeatmapStore());
Dependencies.Cache(Realm);

Add(detachedBeatmapStore);
Add(beatmapStore);
}

public override void SetUpSteps()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ public partial class TestSceneMultiplayerMatchSongSelect : MultiplayerTestScene
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
DetachedBeatmapStore detachedBeatmapStore;
BeatmapStore beatmapStore;

Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(detachedBeatmapStore = new DetachedBeatmapStore());
Dependencies.Cache(beatmapStore = new RealmDetachedBeatmapStore());
Dependencies.Cache(Realm);

importedBeatmapSet = manager.Import(TestResources.CreateTestBeatmapSetInfo(8, rulesets.AvailableRulesets.ToArray()))!;

Add(detachedBeatmapStore);
Add(beatmapStore);
}

private void setUp()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ public partial class TestScenePlaylistsSongSelect : OnlinePlayTestScene
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
DetachedBeatmapStore detachedBeatmapStore;
BeatmapStore beatmapStore;

Dependencies.Cache(new RealmRulesetStore(Realm));
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default));
Dependencies.Cache(detachedBeatmapStore = new DetachedBeatmapStore());
Dependencies.Cache(beatmapStore = new RealmDetachedBeatmapStore());
Dependencies.Cache(Realm);

var beatmapSet = TestResources.CreateTestBeatmapSetInfo();

manager.Import(beatmapSet);

Add(detachedBeatmapStore);
Add(beatmapStore);
}

public override void SetUpSteps()
Expand Down
6 changes: 3 additions & 3 deletions osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,20 +56,20 @@ public partial class TestScenePlaySongSelect : ScreenTestScene
[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
{
DetachedBeatmapStore detachedBeatmapStore;
BeatmapStore beatmapStore;

// These DI caches are required to ensure for interactive runs this test scene doesn't nuke all user beatmaps in the local install.
// At a point we have isolated interactive test runs enough, this can likely be removed.
Dependencies.Cache(rulesets = new RealmRulesetStore(Realm));
Dependencies.Cache(Realm);
Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, defaultBeatmap = Beatmap.Default));
Dependencies.Cache(detachedBeatmapStore = new DetachedBeatmapStore());
Dependencies.Cache(beatmapStore = new RealmDetachedBeatmapStore());

Dependencies.Cache(music = new MusicController());

// required to get bindables attached
Add(music);
Add(detachedBeatmapStore);
Add(beatmapStore);

Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
}
Expand Down
35 changes: 35 additions & 0 deletions osu.Game/Database/BeatmapStore.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Threading;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;

namespace osu.Game.Database
{
/// <summary>
/// A store which contains a thread-safe representation of beatmaps available game-wide.
/// This exposes changes to available beatmaps, such as post-import or deletion.
/// </summary>
/// <remarks>
/// The main goal of classes which implement this interface should be to provide change
/// tracking and thread safety in a performant way, rather than having to worry about such
/// concerns at the point of usage.
/// </remarks>
public abstract partial class BeatmapStore : Component
{
/// <summary>
/// Get all available beatmaps.
/// </summary>
/// <param name="cancellationToken">A cancellation token which allows early abort from the operation.</param>
/// <returns>A bindable list of all available beatmap sets.</returns>
/// <remarks>
/// This operation may block during the initial load process.
///
/// It is generally expected that once a beatmap store is in a good state, the overhead of this call
/// should be negligible.
/// </remarks>
public abstract IBindableList<BeatmapSetInfo> GetBeatmaps(CancellationToken? cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using Realms;

namespace osu.Game.Database
{
public partial class DetachedBeatmapStore : Component
public partial class RealmDetachedBeatmapStore : BeatmapStore
{
private readonly ManualResetEventSlim loaded = new ManualResetEventSlim();

Expand All @@ -28,7 +27,7 @@ public partial class DetachedBeatmapStore : Component
[Resolved]
private RealmAccess realm { get; set; } = null!;

public IBindableList<BeatmapSetInfo> GetDetachedBeatmaps(CancellationToken? cancellationToken)
public override IBindableList<BeatmapSetInfo> GetBeatmaps(CancellationToken? cancellationToken)
{
loaded.Wait(cancellationToken ?? CancellationToken.None);
return detachedBeatmapSets.GetBoundCopy();
Expand Down
2 changes: 1 addition & 1 deletion osu.Game/OsuGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ protected override void LoadComplete()
loadComponentSingleFile(new MedalOverlay(), topMostOverlayContent.Add);

loadComponentSingleFile(new BackgroundDataStoreProcessor(), Add);
loadComponentSingleFile(new DetachedBeatmapStore(), Add, true);
loadComponentSingleFile<BeatmapStore>(new RealmDetachedBeatmapStore(), Add, true);

Add(externalLinkOpener = new ExternalLinkOpener());
Add(new MusicKeyBindingHandler());
Expand Down
6 changes: 3 additions & 3 deletions osu.Game/Screens/Select/BeatmapCarousel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public partial class BeatmapCarousel : CompositeDrawable, IKeyBindingHandler<Glo
private RealmAccess realm { get; set; } = null!;

[Resolved]
private DetachedBeatmapStore? detachedBeatmapStore { get; set; }
private BeatmapStore? beatmapStore { get; set; }

private IBindableList<BeatmapSetInfo>? detachedBeatmapSets;

Expand Down Expand Up @@ -244,9 +244,9 @@ private void load(OsuConfigManager config, AudioManager audio, CancellationToken

RightClickScrollingEnabled.BindValueChanged(enabled => Scroll.RightMouseScrollbar = enabled.NewValue, true);

if (detachedBeatmapStore != null && detachedBeatmapSets == null)
if (beatmapStore != null && detachedBeatmapSets == null)
{
detachedBeatmapSets = detachedBeatmapStore.GetDetachedBeatmaps(cancellationToken);
detachedBeatmapSets = beatmapStore.GetBeatmaps(cancellationToken);
detachedBeatmapSets.BindCollectionChanged(beatmapSetsChanged);
loadNewRoot();
}
Expand Down

0 comments on commit 06d5cf9

Please sign in to comment.