1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 19:22:54 +08:00

Merge branch 'master' into participants-bindable

This commit is contained in:
Dean Herbert 2020-02-13 19:31:50 +09:00 committed by GitHub
commit 28ca1a5bcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 253 additions and 131 deletions

View File

@ -54,6 +54,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.207.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2020.213.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -121,10 +121,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{ {
room.Playlist.Add(new PlaylistItem room.Playlist.Add(new PlaylistItem
{ {
Ruleset = ruleset, Ruleset = { Value = ruleset },
Beatmap = new BeatmapInfo Beatmap =
{ {
Metadata = new BeatmapMetadata() Value = new BeatmapInfo
{
Metadata = new BeatmapMetadata()
}
} }
}); });
} }

View File

@ -32,11 +32,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
Origin = Anchor.Centre, Origin = Anchor.Centre,
}); });
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } }); Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } });
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } }); Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } });
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } }); Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } });
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } }); Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } });
Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } }); Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } });
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -23,16 +23,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
{ {
Room.Playlist.Add(new PlaylistItem Room.Playlist.Add(new PlaylistItem
{ {
Beatmap = new BeatmapInfo Beatmap =
{ {
Metadata = new BeatmapMetadata Value = new BeatmapInfo
{ {
Title = "Title", Metadata = new BeatmapMetadata
Artist = "Artist", {
AuthorString = "Author", Title = "Title",
}, Artist = "Artist",
Version = "Version", AuthorString = "Author",
Ruleset = new OsuRuleset().RulesetInfo },
Version = "Version",
Ruleset = new OsuRuleset().RulesetInfo
}
}, },
RequiredMods = RequiredMods =
{ {

View File

@ -37,16 +37,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
Room.Playlist.Clear(); Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem Room.Playlist.Add(new PlaylistItem
{ {
Beatmap = new BeatmapInfo Beatmap =
{ {
StarDifficulty = 2.4, Value = new BeatmapInfo
Ruleset = rulesets.GetRuleset(0),
Metadata = new BeatmapMetadata
{ {
Title = @"My Song", StarDifficulty = 2.4,
Artist = @"VisualTests", Ruleset = rulesets.GetRuleset(0),
AuthorString = @"osu!lazer", 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.Clear();
Room.Playlist.Add(new PlaylistItem Room.Playlist.Add(new PlaylistItem
{ {
Beatmap = new BeatmapInfo Beatmap =
{ {
StarDifficulty = 4.2, Value = new BeatmapInfo
Ruleset = rulesets.GetRuleset(3),
Metadata = new BeatmapMetadata
{ {
Title = @"Your Song", StarDifficulty = 4.2,
Artist = @"Tester", Ruleset = rulesets.GetRuleset(3),
AuthorString = @"Someone", Metadata = new BeatmapMetadata
}, {
Title = @"Your Song",
Artist = @"Tester",
AuthorString = @"Someone",
},
}
} }
}); });
}); });

View File

@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set name", () => Room.Name.Value = "Room name"); AddStep("set name", () => Room.Name.Value = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value); 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); AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
AddStep("clear name", () => Room.Name.Value = ""); AddStep("clear name", () => Room.Name.Value = "");

View File

@ -0,0 +1,40 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. 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(),
}
}
};
});
}
}
}

View File

@ -37,9 +37,9 @@ namespace osu.Game.Tests
trackStore = audioManager.GetTrackStore(getZipReader()); trackStore = audioManager.GetTrackStore(getZipReader());
} }
protected override void Dispose(bool isDisposing) ~WaveformTestBeatmap()
{ {
base.Dispose(isDisposing); // Remove the track store from the audio manager
trackStore?.Dispose(); trackStore?.Dispose();
} }

View File

@ -36,8 +36,9 @@ namespace osu.Game.Beatmaps
using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path)))) using (var stream = new LineBufferedReader(store.GetStream(getPathForFile(BeatmapInfo.Path))))
return Decoder.GetDecoder<Beatmap>(stream).Decode(stream); return Decoder.GetDecoder<Beatmap>(stream).Decode(stream);
} }
catch catch (Exception e)
{ {
Logger.Error(e, "Beatmap failed to load");
return null; return null;
} }
} }
@ -59,8 +60,9 @@ namespace osu.Game.Beatmaps
{ {
return textureStore.Get(getPathForFile(Metadata.BackgroundFile)); return textureStore.Get(getPathForFile(Metadata.BackgroundFile));
} }
catch catch (Exception e)
{ {
Logger.Error(e, "Background failed to load");
return null; return null;
} }
} }
@ -74,8 +76,9 @@ namespace osu.Game.Beatmaps
{ {
return new VideoSprite(textureStore.GetStream(getPathForFile(Metadata.VideoFile))); return new VideoSprite(textureStore.GetStream(getPathForFile(Metadata.VideoFile)));
} }
catch catch (Exception e)
{ {
Logger.Error(e, "Video failed to load");
return null; return null;
} }
} }
@ -86,8 +89,9 @@ namespace osu.Game.Beatmaps
{ {
return (trackStore ??= AudioManager.GetTrackStore(store)).Get(getPathForFile(Metadata.AudioFile)); return (trackStore ??= AudioManager.GetTrackStore(store)).Get(getPathForFile(Metadata.AudioFile));
} }
catch catch (Exception e)
{ {
Logger.Error(e, "Track failed to load");
return null; return null;
} }
} }
@ -115,8 +119,9 @@ namespace osu.Game.Beatmaps
var trackData = store.GetStream(getPathForFile(Metadata.AudioFile)); var trackData = store.GetStream(getPathForFile(Metadata.AudioFile));
return trackData == null ? null : new Waveform(trackData); return trackData == null ? null : new Waveform(trackData);
} }
catch catch (Exception e)
{ {
Logger.Error(e, "Waveform failed to load");
return null; return null;
} }
} }

View File

@ -17,10 +17,11 @@ using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Framework.Graphics.Video; using osu.Framework.Graphics.Video;
using osu.Framework.Logging;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public abstract class WorkingBeatmap : IWorkingBeatmap, IDisposable public abstract class WorkingBeatmap : IWorkingBeatmap
{ {
public readonly BeatmapInfo BeatmapInfo; public readonly BeatmapInfo BeatmapInfo;
@ -133,11 +134,29 @@ namespace osu.Game.Beatmaps
return converted; return converted;
} }
public override string ToString() => BeatmapInfo.ToString(); private CancellationTokenSource loadCancellation = new CancellationTokenSource();
public bool BeatmapLoaded => beatmapLoadTask?.IsCompleted ?? false; /// <summary>
/// Beings loading the contents of this <see cref="WorkingBeatmap"/> asynchronously.
/// </summary>
public void BeginAsyncLoad()
{
loadBeatmapAsync();
}
public Task<IBeatmap> LoadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() => /// <summary>
/// Cancels the asynchronous loading of the contents of this <see cref="WorkingBeatmap"/>.
/// </summary>
public void CancelAsyncLoad()
{
loadCancellation?.Cancel();
loadCancellation = new CancellationTokenSource();
if (beatmapLoadTask?.IsCompleted != true)
beatmapLoadTask = null;
}
private Task<IBeatmap> loadBeatmapAsync() => beatmapLoadTask ??= Task.Factory.StartNew(() =>
{ {
// Todo: Handle cancellation during beatmap parsing // Todo: Handle cancellation during beatmap parsing
var b = GetBeatmap() ?? new Beatmap(); var b = GetBeatmap() ?? new Beatmap();
@ -149,7 +168,11 @@ namespace osu.Game.Beatmaps
b.BeatmapInfo = BeatmapInfo; b.BeatmapInfo = BeatmapInfo;
return b; 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 public IBeatmap Beatmap
{ {
@ -157,16 +180,25 @@ namespace osu.Game.Beatmaps
{ {
try 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; return null;
} }
} }
} }
private readonly CancellationTokenSource beatmapCancellation = new CancellationTokenSource();
protected abstract IBeatmap GetBeatmap(); protected abstract IBeatmap GetBeatmap();
private Task<IBeatmap> beatmapLoadTask; private Task<IBeatmap> beatmapLoadTask;
@ -217,40 +249,11 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public virtual void RecycleTrack() => track.Recycle(); 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() ~WorkingBeatmap()
{ {
Dispose(false); total_count.Value--;
} }
#endregion
public class RecyclableLazy<T> public class RecyclableLazy<T>
{ {
private Lazy<T> lazy; private Lazy<T> lazy;

View File

@ -55,7 +55,7 @@ namespace osu.Game.Online.Leaderboards
private List<ScoreComponentLabel> statisticsLabels; private List<ScoreComponentLabel> statisticsLabels;
[Resolved] [Resolved(CanBeNull = true)]
private DialogOverlay dialogOverlay { get; set; } private DialogOverlay dialogOverlay { get; set; }
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true) public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)

View File

@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
@ -24,24 +24,16 @@ namespace osu.Game.Online.Multiplayer
public int RulesetID { get; set; } public int RulesetID { get; set; }
[JsonIgnore] [JsonIgnore]
public BeatmapInfo Beatmap public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
{
get => beatmap;
set
{
beatmap = value;
BeatmapID = value?.OnlineBeatmapID ?? 0;
}
}
[JsonIgnore] [JsonIgnore]
public RulesetInfo Ruleset { get; set; } public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
[JsonIgnore] [JsonIgnore]
public readonly List<Mod> AllowedMods = new List<Mod>(); public readonly BindableList<Mod> AllowedMods = new BindableList<Mod>();
[JsonIgnore] [JsonIgnore]
public readonly List<Mod> RequiredMods = new List<Mod>(); public readonly BindableList<Mod> RequiredMods = new BindableList<Mod>();
[JsonProperty("beatmap")] [JsonProperty("beatmap")]
private APIBeatmap apiBeatmap { get; set; } private APIBeatmap apiBeatmap { get; set; }
@ -64,16 +56,20 @@ namespace osu.Game.Online.Multiplayer
set => requiredModsBacking = value; 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) 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 // 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 // Todo: Is this a bug? Room creation only returns the beatmap ID
Beatmap = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets); Beatmap.Value = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets);
Ruleset = rulesets.GetRuleset(RulesetID); Ruleset.Value = rulesets.GetRuleset(RulesetID);
Ruleset rulesetInstance = Ruleset.CreateInstance(); Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
if (allowedModsBacking != null) if (allowedModsBacking != null)
{ {

View File

@ -401,15 +401,14 @@ namespace osu.Game
if (nextBeatmap?.Track != null) if (nextBeatmap?.Track != null)
nextBeatmap.Track.Completed += currentTrackCompleted; nextBeatmap.Track.Completed += currentTrackCompleted;
using (var oldBeatmap = beatmap.OldValue) var oldBeatmap = beatmap.OldValue;
{ if (oldBeatmap?.Track != null)
if (oldBeatmap?.Track != null) oldBeatmap.Track.Completed -= currentTrackCompleted;
oldBeatmap.Track.Completed -= currentTrackCompleted;
}
updateModDefaults(); updateModDefaults();
nextBeatmap?.LoadBeatmapAsync(); oldBeatmap?.CancelAsyncLoad();
nextBeatmap?.BeginAsyncLoad();
} }
private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods) private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)

View File

@ -6,10 +6,13 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input;
namespace osu.Game.Screens.Edit.Compose.Components.Timeline 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); HoverColour = OsuColour.Gray(0.25f);
FlashColour = OsuColour.Gray(0.5f); FlashColour = OsuColour.Gray(0.5f);
} }
private ScheduledDelegate repeatSchedule;
/// <summary>
/// The initial delay before mouse down repeat begins.
/// </summary>
private const int repeat_initial_delay = 250;
/// <summary>
/// The delay between mouse down repeats after the initial repeat.
/// </summary>
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);
}
} }
} }
} }

View File

@ -95,7 +95,7 @@ namespace osu.Game.Screens.Menu
private void updateAmplitudes() private void updateAmplitudes()
{ {
var track = beatmap.Value.TrackLoaded ? beatmap.Value.Track : null; 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; float[] temporalAmplitudes = track?.CurrentAmplitudes.FrequencyAmplitudes;

View File

@ -70,7 +70,7 @@ namespace osu.Game.Screens.Multi.Components
{ {
new OsuSpriteText 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), Font = OsuFont.GetFont(size: TextSize),
}, },
new OsuSpriteText new OsuSpriteText
@ -80,10 +80,10 @@ namespace osu.Game.Screens.Multi.Components
}, },
new OsuSpriteText 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), Font = OsuFont.GetFont(size: TextSize),
} }
}, LinkAction.OpenBeatmap, beatmap.OnlineBeatmapID.ToString(), "Open beatmap"); }, LinkAction.OpenBeatmap, beatmap.Value.OnlineBeatmapID.ToString(), "Open beatmap");
} }
} }
} }

View File

@ -59,7 +59,7 @@ namespace osu.Game.Screens.Multi.Components
if (beatmap != null) if (beatmap != null)
{ {
beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f)); beatmapAuthor.AddText("mapped by ", s => s.Colour = OsuColour.Gray(0.8f));
beatmapAuthor.AddUserLink(beatmap.Metadata.Author); beatmapAuthor.AddUserLink(beatmap.Value.Metadata.Author);
} }
}, true); }, true);
} }

View File

@ -56,7 +56,7 @@ namespace osu.Game.Screens.Multi.Components
if (item?.Beatmap != null) if (item?.Beatmap != null)
{ {
drawableRuleset.FadeIn(transition_duration); 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 else
drawableRuleset.FadeOut(transition_duration); drawableRuleset.FadeOut(transition_duration);

View File

@ -23,7 +23,7 @@ namespace osu.Game.Screens.Multi.Components
InternalChild = sprite = CreateBackgroundSprite(); 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 }; protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both };

View File

@ -68,7 +68,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
{ {
bool matchingFilter = true; 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)) if (!string.IsNullOrEmpty(criteria.SearchString))
matchingFilter &= r.FilterTerms.Any(term => term.IndexOf(criteria.SearchString, StringComparison.InvariantCultureIgnoreCase) >= 0); matchingFilter &= r.FilterTerms.Any(term => term.IndexOf(criteria.SearchString, StringComparison.InvariantCultureIgnoreCase) >= 0);

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;

View File

@ -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); hostInfo.Host.BindTo(Host);
} }

View File

@ -32,7 +32,7 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() 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) private void loadNewPanel(BeatmapInfo beatmap)

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -183,13 +184,13 @@ namespace osu.Game.Screens.Multi.Match
private void currentItemChanged(ValueChangedEvent<PlaylistItem> e) private void currentItemChanged(ValueChangedEvent<PlaylistItem> e)
{ {
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info // 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); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>(); Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
if (e.NewValue?.Ruleset != null) if (e.NewValue?.Ruleset != null)
Ruleset.Value = e.NewValue.Ruleset; Ruleset.Value = e.NewValue.Ruleset.Value;
previewTrackManager.StopAnyPlaying(this); previewTrackManager.StopAnyPlaying(this);
} }
@ -206,7 +207,7 @@ namespace osu.Game.Screens.Multi.Match
return; return;
// Try to retrieve the corresponding local beatmap // 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) if (localBeatmap != null)
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);

View File

@ -50,10 +50,10 @@ namespace osu.Game.Screens.Multi.Play
bool failed = false; bool failed = false;
// Sanity checks to ensure that TimeshiftPlayer matches the settings for the current PlaylistItem // 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"); 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"); throw new InvalidOperationException("Current Ruleset does not match PlaylistItem's Ruleset");
if (!playlistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals))) if (!playlistItem.RequiredMods.All(m => Mods.Value.Any(m.Equals)))

View File

@ -24,7 +24,7 @@ namespace osu.Game.Screens.Play.HUD
public bool DisplayUnrankedText = true; public bool DisplayUnrankedText = true;
public bool AllowExpand = true; public ExpansionMode ExpansionMode = ExpansionMode.ExpandOnHover;
private readonly Bindable<IReadOnlyList<Mod>> current = new Bindable<IReadOnlyList<Mod>>(); private readonly Bindable<IReadOnlyList<Mod>> current = new Bindable<IReadOnlyList<Mod>>();
@ -110,11 +110,15 @@ namespace osu.Game.Screens.Play.HUD
private void expand() private void expand()
{ {
if (AllowExpand) if (ExpansionMode != ExpansionMode.AlwaysContracted)
IconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, Easing.OutQuint); 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) protected override bool OnHover(HoverEvent e)
{ {
@ -128,4 +132,22 @@ namespace osu.Game.Screens.Play.HUD
base.OnHoverLost(e); base.OnHoverLost(e);
} }
} }
public enum ExpansionMode
{
/// <summary>
/// The <see cref="ModDisplay"/> will expand only when hovered.
/// </summary>
ExpandOnHover,
/// <summary>
/// The <see cref="ModDisplay"/> will always be expanded.
/// </summary>
AlwaysExpanded,
/// <summary>
/// The <see cref="ModDisplay"/> will always be contracted.
/// </summary>
AlwaysContracted
}
} }

View File

@ -91,7 +91,7 @@ namespace osu.Game.Screens.Select
public FooterModDisplay() public FooterModDisplay()
{ {
AllowExpand = false; ExpansionMode = ExpansionMode.AlwaysContracted;
IconsContainer.Margin = new MarginPadding(); IconsContainer.Margin = new MarginPadding();
} }
} }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Linq;
using Humanizer; using Humanizer;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -38,8 +39,8 @@ namespace osu.Game.Screens.Select
{ {
var item = new PlaylistItem var item = new PlaylistItem
{ {
Beatmap = Beatmap.Value.BeatmapInfo, Beatmap = { Value = Beatmap.Value.BeatmapInfo },
Ruleset = Ruleset.Value, Ruleset = { Value = Ruleset.Value },
RulesetID = Ruleset.Value.ID ?? 0 RulesetID = Ruleset.Value.ID ?? 0
}; };
@ -60,8 +61,8 @@ namespace osu.Game.Screens.Select
if (CurrentItem.Value != null) if (CurrentItem.Value != null)
{ {
Ruleset.Value = CurrentItem.Value.Ruleset; Ruleset.Value = CurrentItem.Value.Ruleset.Value;
Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap); Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap.Value);
Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty<Mod>(); Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
} }

View File

@ -191,9 +191,9 @@ namespace osu.Game.Tests.Visual
track = audio?.Tracks.GetVirtual(length); 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(); store?.Dispose();
} }

View File

@ -23,7 +23,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.207.0" /> <PackageReference Include="ppy.osu.Framework" Version="2020.213.0" />
<PackageReference Include="Sentry" Version="2.0.2" /> <PackageReference Include="Sentry" Version="2.0.2" />
<PackageReference Include="SharpCompress" Version="0.24.0" /> <PackageReference Include="SharpCompress" Version="0.24.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />

View File

@ -74,7 +74,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.1230.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.207.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2020.213.0" />
</ItemGroup> </ItemGroup>
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. --> <!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
@ -82,7 +82,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2020.207.0" /> <PackageReference Include="ppy.osu.Framework" Version="2020.213.0" />
<PackageReference Include="SharpCompress" Version="0.24.0" /> <PackageReference Include="SharpCompress" Version="0.24.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" /> <PackageReference Include="SharpRaven" Version="2.4.0" />