diff --git a/osu.Android.props b/osu.Android.props
index 25bde037db..494842f38f 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -54,6 +54,6 @@
-
+
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
index fe14a1ff0a..b5d946d049 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
@@ -121,10 +121,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
room.Playlist.Add(new PlaylistItem
{
- Ruleset = ruleset,
- Beatmap = new BeatmapInfo
+ Ruleset = { Value = ruleset },
+ Beatmap =
{
- Metadata = new BeatmapMetadata()
+ Value = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata()
+ }
}
});
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
index 1e3e06ce7a..84ab6f9ccc 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
@@ -32,11 +32,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
Origin = Anchor.Centre,
});
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } });
}
protected override void LoadComplete()
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs
index e42042f2ea..7d7e7f85db 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs
@@ -23,16 +23,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Room.Playlist.Add(new PlaylistItem
{
- Beatmap = new BeatmapInfo
+ Beatmap =
{
- Metadata = new BeatmapMetadata
+ Value = new BeatmapInfo
{
- Title = "Title",
- Artist = "Artist",
- AuthorString = "Author",
- },
- Version = "Version",
- Ruleset = new OsuRuleset().RulesetInfo
+ Metadata = new BeatmapMetadata
+ {
+ Title = "Title",
+ Artist = "Artist",
+ AuthorString = "Author",
+ },
+ Version = "Version",
+ Ruleset = new OsuRuleset().RulesetInfo
+ }
},
RequiredMods =
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs
index a6c036a876..6ee9ceb2dd 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs
@@ -37,16 +37,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem
{
- Beatmap = new BeatmapInfo
+ Beatmap =
{
- StarDifficulty = 2.4,
- Ruleset = rulesets.GetRuleset(0),
- Metadata = new BeatmapMetadata
+ Value = new BeatmapInfo
{
- Title = @"My Song",
- Artist = @"VisualTests",
- AuthorString = @"osu!lazer",
- },
+ StarDifficulty = 2.4,
+ Ruleset = rulesets.GetRuleset(0),
+ Metadata = new BeatmapMetadata
+ {
+ Title = @"My Song",
+ Artist = @"VisualTests",
+ AuthorString = @"osu!lazer",
+ },
+ }
}
});
});
@@ -60,16 +63,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem
{
- Beatmap = new BeatmapInfo
+ Beatmap =
{
- StarDifficulty = 4.2,
- Ruleset = rulesets.GetRuleset(3),
- Metadata = new BeatmapMetadata
+ Value = new BeatmapInfo
{
- Title = @"Your Song",
- Artist = @"Tester",
- AuthorString = @"Someone",
- },
+ StarDifficulty = 4.2,
+ Ruleset = rulesets.GetRuleset(3),
+ Metadata = new BeatmapMetadata
+ {
+ Title = @"Your Song",
+ Artist = @"Tester",
+ AuthorString = @"Someone",
+ },
+ }
}
});
});
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
index 8d842fc865..047e9d860d 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set name", () => Room.Name.Value = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
- AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo }));
+ AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } }));
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
AddStep("clear name", () => Room.Name.Value = "");
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
new file mode 100644
index 0000000000..8168faa106
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
@@ -0,0 +1,40 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Screens.Play.HUD;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneModDisplay : OsuTestScene
+ {
+ [TestCase(ExpansionMode.ExpandOnHover)]
+ [TestCase(ExpansionMode.AlwaysExpanded)]
+ [TestCase(ExpansionMode.AlwaysContracted)]
+ public void TestMode(ExpansionMode mode)
+ {
+ AddStep("create mod display", () =>
+ {
+ Child = new ModDisplay
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ ExpansionMode = mode,
+ Current =
+ {
+ Value = new Mod[]
+ {
+ new OsuModHardRock(),
+ new OsuModDoubleTime(),
+ new OsuModDifficultyAdjust(),
+ new OsuModEasy(),
+ }
+ }
+ };
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs
index df6394ed34..53ce5def32 100644
--- a/osu.Game.Tests/WaveformTestBeatmap.cs
+++ b/osu.Game.Tests/WaveformTestBeatmap.cs
@@ -37,9 +37,9 @@ namespace osu.Game.Tests
trackStore = audioManager.GetTrackStore(getZipReader());
}
- protected override void Dispose(bool isDisposing)
+ ~WaveformTestBeatmap()
{
- base.Dispose(isDisposing);
+ // Remove the track store from the audio manager
trackStore?.Dispose();
}
diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs
index f9d71a2a6e..55c5175c5d 100644
--- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs
@@ -36,8 +36,9 @@ namespace osu.Game.Beatmaps
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
return Decoder.GetDecoder(stream).Decode(stream);
}
- catch
+ catch (Exception e)
{
+ Logger.Error(e, "Beatmap failed to load");
return null;
}
}
@@ -59,8 +60,9 @@ namespace osu.Game.Beatmaps
{
return textureStore.Get(getPathForFile(Metadata.BackgroundFile));
}
- catch
+ catch (Exception e)
{
+ Logger.Error(e, "Background failed to load");
return null;
}
}
@@ -74,8 +76,9 @@ namespace osu.Game.Beatmaps
{
return new VideoSprite(textureStore.GetStream(getPathForFile(Metadata.VideoFile)));
}
- catch
+ catch (Exception e)
{
+ Logger.Error(e, "Video failed to load");
return null;
}
}
@@ -86,8 +89,9 @@ namespace osu.Game.Beatmaps
{
return (trackStore ??= AudioManager.GetTrackStore(store)).Get(getPathForFile(Metadata.AudioFile));
}
- catch
+ catch (Exception e)
{
+ Logger.Error(e, "Track failed to load");
return null;
}
}
@@ -115,8 +119,9 @@ namespace osu.Game.Beatmaps
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new Waveform(trackData);
}
- catch
+ catch (Exception e)
{
+ Logger.Error(e, "Waveform failed to load");
return null;
}
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 5dc483b61c..1e1ffad81e 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -17,10 +17,11 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI;
using osu.Game.Skinning;
using osu.Framework.Graphics.Video;
+using osu.Framework.Logging;
namespace osu.Game.Beatmaps
{
- public abstract class WorkingBeatmap : IWorkingBeatmap, IDisposable
+ public abstract class WorkingBeatmap : IWorkingBeatmap
{
public readonly BeatmapInfo BeatmapInfo;
@@ -133,11 +134,29 @@ namespace osu.Game.Beatmaps
return converted;
}
- public override string ToString() => BeatmapInfo.ToString();
+ private CancellationTokenSource loadCancellation = new CancellationTokenSource();
- public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
+ ///
+ /// Beings loading the contents of this asynchronously.
+ ///
+ public void BeginAsyncLoad()
+ {
+ loadBeatmapAsync();
+ }
- public Task LoadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() =>
+ ///
+ /// Cancels the asynchronous loading of the contents of this .
+ ///
+ public void CancelAsyncLoad()
+ {
+ loadCancellation?.Cancel();
+ loadCancellation = new CancellationTokenSource();
+
+ if (beatmapLoadTask?.IsCompleted != true)
+ beatmapLoadTask = null;
+ }
+
+ private Task loadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() =>
{
// Todo: Handle cancellation during beatmap parsing
var b = GetBeatmap() ?? new Beatmap();
@@ -149,7 +168,11 @@ namespace osu.Game.Beatmaps
b.BeatmapInfo = BeatmapInfo;
return b;
- }, beatmapCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+ }, loadCancellation.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+
+ public override string ToString() => BeatmapInfo.ToString();
+
+ public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false;
public IBeatmap Beatmap
{
@@ -157,16 +180,25 @@ namespace osu.Game.Beatmaps
{
try
{
- return LoadBeatmapAsync().Result;
+ return loadBeatmapAsync().Result;
}
- catch (TaskCanceledException)
+ catch (AggregateException ae)
{
+ // This is the exception that is generally expected here, which occurs via natural cancellation of the asynchronous load
+ if (ae.InnerExceptions.FirstOrDefault() is TaskCanceledException)
+ return null;
+
+ Logger.Error(ae, "Beatmap failed to load");
+ return null;
+ }
+ catch (Exception e)
+ {
+ Logger.Error(e, "Beatmap failed to load");
return null;
}
}
}
- private readonly CancellationTokenSource beatmapCancellation = new CancellationTokenSource();
protected abstract IBeatmap GetBeatmap();
private Task beatmapLoadTask;
@@ -217,40 +249,11 @@ namespace osu.Game.Beatmaps
///
public virtual void RecycleTrack() => track.Recycle();
- #region Disposal
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private bool isDisposed;
-
- protected virtual void Dispose(bool isDisposing)
- {
- if (isDisposed)
- return;
-
- isDisposed = true;
-
- // recycling logic is not here for the time being, as components which use
- // retrieved objects from WorkingBeatmap may not hold a reference to the WorkingBeatmap itself.
- // this should be fine as each retrieved component do have their own finalizers.
-
- // cancelling the beatmap load is safe for now since the retrieval is a synchronous
- // operation. if we add an async retrieval method this may need to be reconsidered.
- beatmapCancellation?.Cancel();
- total_count.Value--;
- }
-
~WorkingBeatmap()
{
- Dispose(false);
+ total_count.Value--;
}
- #endregion
-
public class RecyclableLazy
{
private Lazy lazy;
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index c9131883bb..1f52a4481b 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -55,7 +55,7 @@ namespace osu.Game.Online.Leaderboards
private List statisticsLabels;
- [Resolved]
+ [Resolved(CanBeNull = true)]
private DialogOverlay dialogOverlay { get; set; }
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Multiplayer/PlaylistItem.cs
index 5f8edc607b..e243cfca08 100644
--- a/osu.Game/Online/Multiplayer/PlaylistItem.cs
+++ b/osu.Game/Online/Multiplayer/PlaylistItem.cs
@@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
+using osu.Framework.Bindables;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
@@ -24,24 +24,16 @@ namespace osu.Game.Online.Multiplayer
public int RulesetID { get; set; }
[JsonIgnore]
- public BeatmapInfo Beatmap
- {
- get => beatmap;
- set
- {
- beatmap = value;
- BeatmapID = value?.OnlineBeatmapID ?? 0;
- }
- }
+ public readonly Bindable Beatmap = new Bindable();
[JsonIgnore]
- public RulesetInfo Ruleset { get; set; }
+ public readonly Bindable Ruleset = new Bindable();
[JsonIgnore]
- public readonly List AllowedMods = new List();
+ public readonly BindableList AllowedMods = new BindableList();
[JsonIgnore]
- public readonly List RequiredMods = new List();
+ public readonly BindableList RequiredMods = new BindableList();
[JsonProperty("beatmap")]
private APIBeatmap apiBeatmap { get; set; }
@@ -64,16 +56,20 @@ namespace osu.Game.Online.Multiplayer
set => requiredModsBacking = value;
}
- private BeatmapInfo beatmap;
+ public PlaylistItem()
+ {
+ Beatmap.BindValueChanged(beatmap => BeatmapID = beatmap.NewValue?.OnlineBeatmapID ?? 0);
+ Ruleset.BindValueChanged(ruleset => RulesetID = ruleset.NewValue?.ID ?? 0);
+ }
public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets)
{
// If we don't have an api beatmap, the request occurred as a result of room creation, so we can query the local beatmap instead
// Todo: Is this a bug? Room creation only returns the beatmap ID
- Beatmap = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets);
- Ruleset = rulesets.GetRuleset(RulesetID);
+ Beatmap.Value = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets);
+ Ruleset.Value = rulesets.GetRuleset(RulesetID);
- Ruleset rulesetInstance = Ruleset.CreateInstance();
+ Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
if (allowedModsBacking != null)
{
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 79616ef97c..e7fffd49b4 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -401,15 +401,14 @@ namespace osu.Game
if (nextBeatmap?.Track != null)
nextBeatmap.Track.Completed += currentTrackCompleted;
- using (var oldBeatmap = beatmap.OldValue)
- {
- if (oldBeatmap?.Track != null)
- oldBeatmap.Track.Completed -= currentTrackCompleted;
- }
+ var oldBeatmap = beatmap.OldValue;
+ if (oldBeatmap?.Track != null)
+ oldBeatmap.Track.Completed -= currentTrackCompleted;
updateModDefaults();
- nextBeatmap?.LoadBeatmapAsync();
+ oldBeatmap?.CancelAsyncLoad();
+ nextBeatmap?.BeginAsyncLoad();
}
private void modsChanged(ValueChangedEvent> mods)
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs
index 8865bf31ea..5550c6a748 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineButton.cs
@@ -6,10 +6,13 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Input.Events;
+using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
+using osuTK.Input;
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
@@ -52,6 +55,45 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
HoverColour = OsuColour.Gray(0.25f);
FlashColour = OsuColour.Gray(0.5f);
}
+
+ private ScheduledDelegate repeatSchedule;
+
+ ///
+ /// The initial delay before mouse down repeat begins.
+ ///
+ private const int repeat_initial_delay = 250;
+
+ ///
+ /// The delay between mouse down repeats after the initial repeat.
+ ///
+ private const int repeat_tick_rate = 70;
+
+ protected override bool OnClick(ClickEvent e)
+ {
+ // don't actuate a click since we are manually handling repeats.
+ return true;
+ }
+
+ protected override bool OnMouseDown(MouseDownEvent e)
+ {
+ if (e.Button == MouseButton.Left)
+ {
+ Action clickAction = () => base.OnClick(new ClickEvent(e.CurrentState, e.Button));
+
+ // run once for initial down
+ clickAction();
+
+ Scheduler.Add(repeatSchedule = new ScheduledDelegate(clickAction, Clock.CurrentTime + repeat_initial_delay, repeat_tick_rate));
+ }
+
+ return base.OnMouseDown(e);
+ }
+
+ protected override void OnMouseUp(MouseUpEvent e)
+ {
+ repeatSchedule?.Cancel();
+ base.OnMouseUp(e);
+ }
}
}
}
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index 06ca161fed..dcc68296f6 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -95,7 +95,7 @@ namespace osu.Game.Screens.Menu
private void updateAmplitudes()
{
var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null;
- var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null;
+ var effect = beatmap.Value.BeatmapLoaded ? beatmap.Value.Beatmap?.ControlPointInfo.EffectPointAt(track?.CurrentTime ?? Time.Current) : null;
float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes;
diff --git a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
index b41b2d073e..b991a3d68d 100644
--- a/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
+++ b/osu.Game/Screens/Multi/Components/BeatmapTitle.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Screens.Multi.Components
{
new OsuSpriteText
{
- Text = new LocalisedString((beatmap.Metadata.ArtistUnicode, beatmap.Metadata.Artist)),
+ Text = new LocalisedString((beatmap.Value.Metadata.ArtistUnicode, beatmap.Value.Metadata.Artist)),
Font = OsuFont.GetFont(size: TextSize),
},
new OsuSpriteText
@@ -80,10 +80,10 @@ namespace osu.Game.Screens.Multi.Components
},
new OsuSpriteText
{
- Text = new LocalisedString((beatmap.Metadata.TitleUnicode, beatmap.Metadata.Title)),
+ Text = new LocalisedString((beatmap.Value.Metadata.TitleUnicode, beatmap.Value.Metadata.Title)),
Font = OsuFont.GetFont(size: TextSize),
}
- }, LinkAction.OpenBeatmap, beatmap.OnlineBeatmapID.ToString(), "Open beatmap");
+ }, LinkAction.OpenBeatmap, beatmap.Value.OnlineBeatmapID.ToString(), "Open beatmap");
}
}
}
diff --git a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs
index d63f2fecd2..21b228bb5c 100644
--- a/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs
+++ b/osu.Game/Screens/Multi/Components/BeatmapTypeInfo.cs
@@ -59,7 +59,7 @@ namespace osu.Game.Screens.Multi.Components
if (beatmap != null)
{
beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f));
- beatmapAuthor.AddUserLink(beatmap.Metadata.Author);
+ beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author);
}
}, true);
}
diff --git a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs
index 6080458aec..5465463888 100644
--- a/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs
+++ b/osu.Game/Screens/Multi/Components/ModeTypeInfo.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Screens.Multi.Components
if (item?.Beatmap != null)
{
drawableRuleset.FadeIn(transition_duration);
- drawableRuleset.Child = new DifficultyIcon(item.Beatmap, item.Ruleset) { Size = new Vector2(height) };
+ drawableRuleset.Child = new DifficultyIcon(item.Beatmap.Value, item.Ruleset.Value) { Size = new Vector2(height) };
}
else
drawableRuleset.FadeOut(transition_duration);
diff --git a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs
index 968fa6e72e..9a1a482699 100644
--- a/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs
+++ b/osu.Game/Screens/Multi/Components/MultiplayerBackgroundSprite.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Multi.Components
InternalChild = sprite = CreateBackgroundSprite();
- CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap, true);
+ CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap.Value, true);
}
protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both };
diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
index 063957d816..64618a1d85 100644
--- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
+++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
@@ -68,7 +68,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
{
bool matchingFilter = true;
- matchingFilter &= r.Room.Playlist.Count == 0 || r.Room.Playlist.Any(i => i.Ruleset.Equals(criteria.Ruleset));
+ matchingFilter &= r.Room.Playlist.Count == 0 || r.Room.Playlist.Any(i => i.Ruleset.Value.Equals(criteria.Ruleset));
if (!string.IsNullOrEmpty(criteria.SearchString))
matchingFilter &= r.FilterTerms.Any(term => term.IndexOf(criteria.SearchString, StringComparison.InvariantCultureIgnoreCase) >= 0);
diff --git a/osu.Game/Screens/Multi/Match/Components/Header.cs b/osu.Game/Screens/Multi/Match/Components/Header.cs
index a52d43acf4..991060cac0 100644
--- a/osu.Game/Screens/Multi/Match/Components/Header.cs
+++ b/osu.Game/Screens/Multi/Match/Components/Header.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
diff --git a/osu.Game/Screens/Multi/Match/Components/Info.cs b/osu.Game/Screens/Multi/Match/Components/Info.cs
index 74f000c21f..f0b54baa4c 100644
--- a/osu.Game/Screens/Multi/Match/Components/Info.cs
+++ b/osu.Game/Screens/Multi/Match/Components/Info.cs
@@ -89,7 +89,7 @@ namespace osu.Game.Screens.Multi.Match.Components
},
};
- CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap, true);
+ CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap.Value, true);
hostInfo.Host.BindTo(Host);
}
diff --git a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs
index 7c1fe91393..f67f6d9f43 100644
--- a/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs
+++ b/osu.Game/Screens/Multi/Match/Components/MatchBeatmapPanel.cs
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader]
private void load()
{
- CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap), true);
+ CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap.Value), true);
}
private void loadNewPanel(BeatmapInfo beatmap)
diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
index c2bb7da6b5..9165ef6d0f 100644
--- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
+++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -183,13 +184,13 @@ namespace osu.Game.Screens.Multi.Match
private void currentItemChanged(ValueChangedEvent e)
{
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
- var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.OnlineBeatmapID);
+ var localBeatmap = e.NewValue?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == e.NewValue.Beatmap.Value.OnlineBeatmapID);
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty();
if (e.NewValue?.Ruleset != null)
- Ruleset.Value = e.NewValue.Ruleset;
+ Ruleset.Value = e.NewValue.Ruleset.Value;
previewTrackManager.StopAnyPlaying(this);
}
@@ -206,7 +207,7 @@ namespace osu.Game.Screens.Multi.Match
return;
// Try to retrieve the corresponding local beatmap
- var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == CurrentItem.Value.Beatmap.OnlineBeatmapID);
+ var localBeatmap = beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == CurrentItem.Value.Beatmap.Value.OnlineBeatmapID);
if (localBeatmap != null)
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
index 88c6fc5e2e..3afacf2f31 100644
--- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
+++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
@@ -50,10 +50,10 @@ namespace osu.Game.Screens.Multi.Play
bool failed = false;
// Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem
- if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.OnlineBeatmapID)
+ if (Beatmap.Value.BeatmapInfo.OnlineBeatmapID != playlistItem.Beatmap.Value.OnlineBeatmapID)
throw new InvalidOperationException("Current Beatmap does not match PlaylistItem's Beatmap");
- if (ruleset.Value.ID != playlistItem.Ruleset.ID)
+ if (ruleset.Value.ID != playlistItem.Ruleset.Value.ID)
throw new InvalidOperationException("Current Ruleset does not match PlaylistItem's Ruleset");
if (!playlistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals)))
diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs
index 00edd4db99..336b03544f 100644
--- a/osu.Game/Screens/Play/HUD/ModDisplay.cs
+++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD
public bool DisplayUnrankedText = true;
- public bool AllowExpand = true;
+ public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover;
private readonly Bindable> current = new Bindable>();
@@ -110,11 +110,15 @@ namespace osu.Game.Screens.Play.HUD
private void expand()
{
- if (AllowExpand)
+ if (ExpansionMode != ExpansionMode.AlwaysContracted)
IconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint);
}
- private void contract() => IconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
+ private void contract()
+ {
+ if (ExpansionMode != ExpansionMode.AlwaysExpanded)
+ IconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, Easing.OutQuint);
+ }
protected override bool OnHover(HoverEvent e)
{
@@ -128,4 +132,22 @@ namespace osu.Game.Screens.Play.HUD
base.OnHoverLost(e);
}
}
+
+ public enum ExpansionMode
+ {
+ ///
+ /// The will expand only when hovered.
+ ///
+ ExpandOnHover,
+
+ ///
+ /// The will always be expanded.
+ ///
+ AlwaysExpanded,
+
+ ///
+ /// The will always be contracted.
+ ///
+ AlwaysContracted
+ }
}
diff --git a/osu.Game/Screens/Select/FooterButtonMods.cs b/osu.Game/Screens/Select/FooterButtonMods.cs
index 4f2369847f..2411cf26f9 100644
--- a/osu.Game/Screens/Select/FooterButtonMods.cs
+++ b/osu.Game/Screens/Select/FooterButtonMods.cs
@@ -91,7 +91,7 @@ namespace osu.Game.Screens.Select
public FooterModDisplay()
{
- AllowExpand = false;
+ ExpansionMode = ExpansionMode.AlwaysContracted;
IconsContainer.Margin = new MarginPadding();
}
}
diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs
index 6ba4157797..ff0544d227 100644
--- a/osu.Game/Screens/Select/MatchSongSelect.cs
+++ b/osu.Game/Screens/Select/MatchSongSelect.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -38,8 +39,8 @@ namespace osu.Game.Screens.Select
{
var item = new PlaylistItem
{
- Beatmap = Beatmap.Value.BeatmapInfo,
- Ruleset = Ruleset.Value,
+ Beatmap = { Value = Beatmap.Value.BeatmapInfo },
+ Ruleset = { Value = Ruleset.Value },
RulesetID = Ruleset.Value.ID ?? 0
};
@@ -60,8 +61,8 @@ namespace osu.Game.Screens.Select
if (CurrentItem.Value != null)
{
- Ruleset.Value = CurrentItem.Value.Ruleset;
- Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap);
+ Ruleset.Value = CurrentItem.Value.Ruleset.Value;
+ Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap.Value);
Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty();
}
diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs
index 41ab7fce99..b203557fab 100644
--- a/osu.Game/Tests/Visual/OsuTestScene.cs
+++ b/osu.Game/Tests/Visual/OsuTestScene.cs
@@ -191,9 +191,9 @@ namespace osu.Game.Tests.Visual
track = audio?.Tracks.GetVirtual(length);
}
- protected override void Dispose(bool isDisposing)
+ ~ClockBackedTestWorkingBeatmap()
{
- base.Dispose(isDisposing);
+ // Remove the track store from the audio manager
store?.Dispose();
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 389fbe8210..50d8c25b11 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 3ed25360c5..e56fc41b07 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -74,7 +74,7 @@
-
+
@@ -82,7 +82,7 @@
-
+