1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-16 02:03:51 +08:00

Merge branch 'master' into update-placement-more-often

This commit is contained in:
Dean Herbert 2020-02-13 23:55:18 +09:00 committed by GitHub
commit d7c71cd0c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 287 additions and 226 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,11 +121,14 @@ 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 =
{
Value = new BeatmapInfo
{ {
Metadata = new BeatmapMetadata() Metadata = new BeatmapMetadata()
} }
}
}); });
} }

View File

@ -7,7 +7,6 @@ using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Match.Components; using osu.Game.Screens.Multi.Match.Components;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -32,22 +31,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()
{
base.LoadComplete();
AddStep("Select random beatmap", () =>
{
Room.CurrentItem.Value = Room.Playlist[RNG.Next(Room.Playlist.Count)];
previewTrackManager.StopAnyPlaying(this);
});
} }
} }
} }

View File

@ -23,7 +23,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
{ {
Room.Playlist.Add(new PlaylistItem Room.Playlist.Add(new PlaylistItem
{ {
Beatmap = new BeatmapInfo Beatmap =
{
Value = new BeatmapInfo
{ {
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
{ {
@ -33,6 +35,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
}, },
Version = "Version", Version = "Version",
Ruleset = new OsuRuleset().RulesetInfo Ruleset = new OsuRuleset().RulesetInfo
}
}, },
RequiredMods = RequiredMods =
{ {

View File

@ -37,7 +37,9 @@ 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 =
{
Value = new BeatmapInfo
{ {
StarDifficulty = 2.4, StarDifficulty = 2.4,
Ruleset = rulesets.GetRuleset(0), Ruleset = rulesets.GetRuleset(0),
@ -48,6 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AuthorString = @"osu!lazer", AuthorString = @"osu!lazer",
}, },
} }
}
}); });
}); });
@ -60,7 +63,9 @@ 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 =
{
Value = new BeatmapInfo
{ {
StarDifficulty = 4.2, StarDifficulty = 4.2,
Ruleset = rulesets.GetRuleset(3), Ruleset = rulesets.GetRuleset(3),
@ -71,6 +76,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AuthorString = @"Someone", AuthorString = @"Someone",
}, },
} }
}
}); });
}); });
} }

View File

@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Add(new Participants { RelativeSizeAxes = Axes.Both }); Add(new Participants { RelativeSizeAxes = Axes.Both });
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null); AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
AddStep(@"set users", () => Room.Participants.Value = new[] AddStep(@"set users", () => Room.Participants.AddRange(new[]
{ {
new User new User
{ {
@ -42,10 +42,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg", CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg",
IsSupporter = true, IsSupporter = true,
}, },
}); }));
AddStep(@"set max", () => Room.MaxParticipants.Value = 10); AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
AddStep(@"clear users", () => Room.Participants.Value = System.Array.Empty<User>()); AddStep(@"clear users", () => Room.Participants.Clear());
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null); AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
} }
} }

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

@ -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,10 @@
// 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;
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;
@ -12,7 +13,7 @@ using osu.Game.Rulesets.Mods;
namespace osu.Game.Online.Multiplayer namespace osu.Game.Online.Multiplayer
{ {
public class PlaylistItem public class PlaylistItem : IEquatable<PlaylistItem>
{ {
[JsonProperty("id")] [JsonProperty("id")]
public int ID { get; set; } public int ID { get; set; }
@ -24,24 +25,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 +57,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)
{ {
@ -94,5 +91,14 @@ namespace osu.Game.Online.Multiplayer
public bool ShouldSerializeID() => false; public bool ShouldSerializeID() => false;
public bool ShouldSerializeapiBeatmap() => false; public bool ShouldSerializeapiBeatmap() => false;
public bool Equals(PlaylistItem other) => ID == other?.ID && BeatmapID == other.BeatmapID && RulesetID == other.RulesetID;
public override int GetHashCode()
{
// ReSharper disable NonReadonlyMemberInGetHashCode
return HashCode.Combine(ID, BeatmapID, RulesetID);
// ReSharper restore NonReadonlyMemberInGetHashCode
}
} }
} }

View File

@ -2,7 +2,6 @@
// 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.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -31,10 +30,6 @@ namespace osu.Game.Online.Multiplayer
[JsonProperty("playlist")] [JsonProperty("playlist")]
public BindableList<PlaylistItem> Playlist { get; private set; } = new BindableList<PlaylistItem>(); public BindableList<PlaylistItem> Playlist { get; private set; } = new BindableList<PlaylistItem>();
[Cached]
[JsonIgnore]
public Bindable<PlaylistItem> CurrentItem { get; private set; } = new Bindable<PlaylistItem>();
[Cached] [Cached]
[JsonProperty("channel_id")] [JsonProperty("channel_id")]
public Bindable<int> ChannelId { get; private set; } = new Bindable<int>(); public Bindable<int> ChannelId { get; private set; } = new Bindable<int>();
@ -65,23 +60,11 @@ namespace osu.Game.Online.Multiplayer
[Cached] [Cached]
[JsonIgnore] [JsonIgnore]
public Bindable<IEnumerable<User>> Participants { get; private set; } = new Bindable<IEnumerable<User>>(Enumerable.Empty<User>()); public BindableList<User> Participants { get; private set; } = new BindableList<User>();
[Cached] [Cached]
public Bindable<int> ParticipantCount { get; private set; } = new Bindable<int>(); public Bindable<int> ParticipantCount { get; private set; } = new Bindable<int>();
public Room()
{
Playlist.ItemsAdded += updateCurrent;
Playlist.ItemsRemoved += updateCurrent;
updateCurrent(Playlist);
}
private void updateCurrent(IEnumerable<PlaylistItem> playlist)
{
CurrentItem.Value = playlist.FirstOrDefault();
}
// todo: TEMPORARY // todo: TEMPORARY
[JsonProperty("participant_count")] [JsonProperty("participant_count")]
private int? participantCount private int? participantCount
@ -130,17 +113,18 @@ namespace osu.Game.Online.Multiplayer
Type.Value = other.Type.Value; Type.Value = other.Type.Value;
MaxParticipants.Value = other.MaxParticipants.Value; MaxParticipants.Value = other.MaxParticipants.Value;
ParticipantCount.Value = other.ParticipantCount.Value; ParticipantCount.Value = other.ParticipantCount.Value;
Participants.Value = other.Participants.Value.ToArray();
EndDate.Value = other.EndDate.Value; EndDate.Value = other.EndDate.Value;
if (DateTimeOffset.Now >= EndDate.Value) if (DateTimeOffset.Now >= EndDate.Value)
Status.Value = new RoomStatusEnded(); Status.Value = new RoomStatusEnded();
// Todo: Temporary, should only remove/add new items (requires framework changes) foreach (var removedItem in Playlist.Except(other.Playlist).ToArray())
if (Playlist.Count == 0) Playlist.Remove(removedItem);
Playlist.AddRange(other.Playlist); Playlist.AddRange(other.Playlist.Except(Playlist).ToArray());
else if (other.Playlist.Count > 0)
Playlist.First().ID = other.Playlist.First().ID; foreach (var removedItem in Participants.Except(other.Participants).ToArray())
Participants.Remove(removedItem);
Participants.AddRange(other.Participants.Except(Participants).ToArray());
Position = other.Position; Position = other.Position;
} }

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

@ -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

@ -1,6 +1,7 @@
// 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.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
@ -25,7 +26,10 @@ namespace osu.Game.Screens.Multi.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
CurrentItem.BindValueChanged(_ => updateText(), true); Playlist.ItemsAdded += _ => updateText();
Playlist.ItemsRemoved += _ => updateText();
updateText();
} }
private float textSize = OsuFont.DEFAULT_FONT_SIZE; private float textSize = OsuFont.DEFAULT_FONT_SIZE;
@ -54,7 +58,7 @@ namespace osu.Game.Screens.Multi.Components
textFlow.Clear(); textFlow.Clear();
var beatmap = CurrentItem.Value?.Beatmap; var beatmap = Playlist.FirstOrDefault()?.Beatmap;
if (beatmap == null) if (beatmap == null)
{ {
@ -70,7 +74,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 +84,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

@ -1,6 +1,7 @@
// 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.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -12,6 +13,8 @@ namespace osu.Game.Screens.Multi.Components
{ {
public class BeatmapTypeInfo : MultiplayerComposite public class BeatmapTypeInfo : MultiplayerComposite
{ {
private LinkFlowContainer beatmapAuthor;
public BeatmapTypeInfo() public BeatmapTypeInfo()
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
@ -20,8 +23,6 @@ namespace osu.Game.Screens.Multi.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
LinkFlowContainer beatmapAuthor;
InternalChild = new FillFlowContainer InternalChild = new FillFlowContainer
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -50,18 +51,23 @@ namespace osu.Game.Screens.Multi.Components
} }
}; };
CurrentItem.BindValueChanged(item => Playlist.ItemsAdded += _ => updateInfo();
Playlist.ItemsRemoved += _ => updateInfo();
updateInfo();
}
private void updateInfo()
{ {
beatmapAuthor.Clear(); beatmapAuthor.Clear();
var beatmap = item.NewValue?.Beatmap; var beatmap = Playlist.FirstOrDefault()?.Beatmap;
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);
} }
} }
} }

View File

@ -1,11 +1,11 @@
// 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.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Online.Multiplayer;
using osuTK; using osuTK;
namespace osu.Game.Screens.Multi.Components namespace osu.Game.Screens.Multi.Components
@ -46,17 +46,22 @@ namespace osu.Game.Screens.Multi.Components
}, },
}; };
CurrentItem.BindValueChanged(item => updateBeatmap(item.NewValue), true);
Type.BindValueChanged(type => gameTypeContainer.Child = new DrawableGameType(type.NewValue) { Size = new Vector2(height) }, true); Type.BindValueChanged(type => gameTypeContainer.Child = new DrawableGameType(type.NewValue) { Size = new Vector2(height) }, true);
Playlist.ItemsAdded += _ => updateBeatmap();
Playlist.ItemsRemoved += _ => updateBeatmap();
updateBeatmap();
} }
private void updateBeatmap(PlaylistItem item) private void updateBeatmap()
{ {
var item = Playlist.FirstOrDefault();
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

@ -1,6 +1,7 @@
// 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.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
@ -10,6 +11,7 @@ namespace osu.Game.Screens.Multi.Components
public class MultiplayerBackgroundSprite : MultiplayerComposite public class MultiplayerBackgroundSprite : MultiplayerComposite
{ {
private readonly BeatmapSetCoverType beatmapSetCoverType; private readonly BeatmapSetCoverType beatmapSetCoverType;
private UpdateableBeatmapBackgroundSprite sprite;
public MultiplayerBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) public MultiplayerBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover)
{ {
@ -19,11 +21,17 @@ namespace osu.Game.Screens.Multi.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
UpdateableBeatmapBackgroundSprite sprite;
InternalChild = sprite = CreateBackgroundSprite(); InternalChild = sprite = CreateBackgroundSprite();
CurrentItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap, true); Playlist.ItemsAdded += _ => updateBeatmap();
Playlist.ItemsRemoved += _ => updateBeatmap();
updateBeatmap();
}
private void updateBeatmap()
{
sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value;
} }
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;
@ -32,6 +33,7 @@ namespace osu.Game.Screens.Multi.Match.Components
public Action RequestBeatmapSelection; public Action RequestBeatmapSelection;
private MatchBeatmapPanel beatmapPanel; private MatchBeatmapPanel beatmapPanel;
private ModDisplay modDisplay;
public Header() public Header()
{ {
@ -43,7 +45,6 @@ namespace osu.Game.Screens.Multi.Match.Components
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
BeatmapSelectButton beatmapButton; BeatmapSelectButton beatmapButton;
ModDisplay modDisplay;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
@ -119,9 +120,12 @@ namespace osu.Game.Screens.Multi.Match.Components
}, },
}; };
CurrentItem.BindValueChanged(item => modDisplay.Current.Value = item.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>(), true);
beatmapButton.Action = () => RequestBeatmapSelection?.Invoke(); beatmapButton.Action = () => RequestBeatmapSelection?.Invoke();
Playlist.ItemsAdded += _ => updateMods();
Playlist.ItemsRemoved += _ => updateMods();
updateMods();
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -130,6 +134,13 @@ namespace osu.Game.Screens.Multi.Match.Components
ShowBeatmapPanel.BindValueChanged(value => beatmapPanel.FadeTo(value.NewValue ? 1 : 0, 200, Easing.OutQuint), true); ShowBeatmapPanel.BindValueChanged(value => beatmapPanel.FadeTo(value.NewValue ? 1 : 0, 200, Easing.OutQuint), true);
} }
private void updateMods()
{
var item = Playlist.FirstOrDefault();
modDisplay.Current.Value = item?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
}
private class BeatmapSelectButton : HeaderButton private class BeatmapSelectButton : HeaderButton
{ {
[Resolved(typeof(Room), nameof(Room.RoomID))] [Resolved(typeof(Room), nameof(Room.RoomID))]

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.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -18,6 +19,8 @@ namespace osu.Game.Screens.Multi.Match.Components
{ {
public Action OnStart; public Action OnStart;
private ReadyButton readyButton;
public Info() public Info()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -27,7 +30,6 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
ReadyButton readyButton;
HostInfo hostInfo; HostInfo hostInfo;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
@ -89,9 +91,17 @@ namespace osu.Game.Screens.Multi.Match.Components
}, },
}; };
CurrentItem.BindValueChanged(item => readyButton.Beatmap.Value = item.NewValue?.Beatmap, true);
hostInfo.Host.BindTo(Host); hostInfo.Host.BindTo(Host);
Playlist.ItemsAdded += _ => updateBeatmap();
Playlist.ItemsRemoved += _ => updateBeatmap();
updateBeatmap();
}
private void updateBeatmap()
{
readyButton.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value;
} }
} }
} }

View File

@ -1,10 +1,10 @@
// 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.Linq;
using System.Threading; using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Direct; using osu.Game.Overlays.Direct;
@ -32,10 +32,13 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
CurrentItem.BindValueChanged(item => loadNewPanel(item.NewValue?.Beatmap), true); Playlist.ItemsAdded += _ => loadNewPanel();
Playlist.ItemsRemoved += _ => loadNewPanel();
loadNewPanel();
} }
private void loadNewPanel(BeatmapInfo beatmap) private void loadNewPanel()
{ {
loadCancellation?.Cancel(); loadCancellation?.Cancel();
request?.Cancel(); request?.Cancel();
@ -44,6 +47,8 @@ namespace osu.Game.Screens.Multi.Match.Components
panel?.Expire(); panel?.Expire();
panel = null; panel = null;
var beatmap = Playlist.FirstOrDefault()?.Beatmap.Value;
if (beatmap?.OnlineBeatmapID == null) if (beatmap?.OnlineBeatmapID == null)
return; return;

View File

@ -51,9 +51,9 @@ namespace osu.Game.Screens.Multi.Match.Components
}, },
}; };
Participants.BindValueChanged(participants => Participants.ItemsAdded += users =>
{ {
usersFlow.Children = participants.NewValue.Select(u => usersFlow.AddRange(users.Select(u =>
{ {
var panel = new UserPanel(u) var panel = new UserPanel(u)
{ {
@ -65,8 +65,13 @@ namespace osu.Game.Screens.Multi.Match.Components
panel.OnLoadComplete += d => d.FadeInFromZero(60); panel.OnLoadComplete += d => d.FadeInFromZero(60);
return panel; return panel;
}).ToList(); }).ToList());
}, true); };
Participants.ItemsRemoved += users =>
{
usersFlow.RemoveAll(p => users.Contains(p.User));
};
} }
} }
} }

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;
@ -40,9 +41,6 @@ namespace osu.Game.Screens.Multi.Match
[Resolved(typeof(Room))] [Resolved(typeof(Room))]
protected BindableList<PlaylistItem> Playlist { get; private set; } protected BindableList<PlaylistItem> Playlist { get; private set; }
[Resolved(typeof(Room))]
protected Bindable<PlaylistItem> CurrentItem { get; private set; }
[Resolved] [Resolved]
private BeatmapManager beatmapManager { get; set; } private BeatmapManager beatmapManager { get; set; }
@ -52,6 +50,7 @@ namespace osu.Game.Screens.Multi.Match
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
private OsuGame game { get; set; } private OsuGame game { get; set; }
private readonly Bindable<PlaylistItem> selectedItem = new Bindable<PlaylistItem>();
private MatchLeaderboard leaderboard; private MatchLeaderboard leaderboard;
public MatchSubScreen(Room room) public MatchSubScreen(Room room)
@ -165,7 +164,16 @@ namespace osu.Game.Screens.Multi.Match
{ {
base.LoadComplete(); base.LoadComplete();
CurrentItem.BindValueChanged(currentItemChanged, true); Playlist.ItemsAdded += _ => updateSelectedItem();
Playlist.ItemsRemoved += _ => updateSelectedItem();
updateSelectedItem();
}
private void updateSelectedItem()
{
selectedItem.Value = Playlist.FirstOrDefault();
currentItemChanged();
} }
public override bool OnExiting(IScreen next) public override bool OnExiting(IScreen next)
@ -180,16 +188,18 @@ namespace osu.Game.Screens.Multi.Match
/// <summary> /// <summary>
/// Handles propagation of the current playlist item's content to game-wide mechanisms. /// Handles propagation of the current playlist item's content to game-wide mechanisms.
/// </summary> /// </summary>
private void currentItemChanged(ValueChangedEvent<PlaylistItem> e) private void currentItemChanged()
{ {
var item = selectedItem.Value;
// 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 = item?.Beatmap == null ? null : beatmapManager.QueryBeatmap(b => b.OnlineBeatmapID == item.Beatmap.Value.OnlineBeatmapID);
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
Mods.Value = e.NewValue?.RequiredMods?.ToArray() ?? Array.Empty<Mod>(); Mods.Value = item?.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
if (e.NewValue?.Ruleset != null) if (item?.Ruleset != null)
Ruleset.Value = e.NewValue.Ruleset; Ruleset.Value = item.Ruleset.Value;
previewTrackManager.StopAnyPlaying(this); previewTrackManager.StopAnyPlaying(this);
} }
@ -202,11 +212,11 @@ namespace osu.Game.Screens.Multi.Match
if (Beatmap.Value != beatmapManager.DefaultBeatmap) if (Beatmap.Value != beatmapManager.DefaultBeatmap)
return; return;
if (CurrentItem.Value == null) if (selectedItem.Value == null)
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 == selectedItem.Value.Beatmap.Value.OnlineBeatmapID);
if (localBeatmap != null) if (localBeatmap != null)
Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap); Beatmap.Value = beatmapManager.GetWorkingBeatmap(localBeatmap);
@ -223,7 +233,7 @@ namespace osu.Game.Screens.Multi.Match
{ {
default: default:
case GameTypeTimeshift _: case GameTypeTimeshift _:
multiplayer?.Start(() => new TimeshiftPlayer(CurrentItem.Value) multiplayer?.Start(() => new TimeshiftPlayer(selectedItem.Value)
{ {
Exited = () => leaderboard.RefreshScores() Exited = () => leaderboard.RefreshScores()
}); });

View File

@ -2,7 +2,6 @@
// 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.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -32,10 +31,7 @@ namespace osu.Game.Screens.Multi
protected BindableList<PlaylistItem> Playlist { get; private set; } protected BindableList<PlaylistItem> Playlist { get; private set; }
[Resolved(typeof(Room))] [Resolved(typeof(Room))]
protected Bindable<PlaylistItem> CurrentItem { get; private set; } protected BindableList<User> Participants { get; private set; }
[Resolved(typeof(Room))]
protected Bindable<IEnumerable<User>> Participants { get; private set; }
[Resolved(typeof(Room))] [Resolved(typeof(Room))]
protected Bindable<int> ParticipantCount { get; private set; } protected Bindable<int> ParticipantCount { get; private set; }

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

@ -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;
@ -21,11 +22,11 @@ namespace osu.Game.Screens.Select
public string ShortTitle => "song selection"; public string ShortTitle => "song selection";
public override string Title => ShortTitle.Humanize(); public override string Title => ShortTitle.Humanize();
[Resolved(typeof(Room))]
protected Bindable<PlaylistItem> CurrentItem { get; private set; }
public override bool AllowEditing => false; public override bool AllowEditing => false;
[Resolved(typeof(Room), nameof(Room.Playlist))]
protected BindableList<PlaylistItem> Playlist { get; private set; }
[Resolved] [Resolved]
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
@ -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
}; };
@ -58,11 +59,13 @@ namespace osu.Game.Screens.Select
if (base.OnExiting(next)) if (base.OnExiting(next))
return true; return true;
if (CurrentItem.Value != null) var firstItem = Playlist.FirstOrDefault();
if (firstItem != null)
{ {
Ruleset.Value = CurrentItem.Value.Ruleset; Ruleset.Value = firstItem.Ruleset.Value;
Beatmap.Value = beatmaps.GetWorkingBeatmap(CurrentItem.Value.Beatmap); Beatmap.Value = beatmaps.GetWorkingBeatmap(firstItem.Beatmap.Value);
Mods.Value = CurrentItem.Value.RequiredMods?.ToArray() ?? Array.Empty<Mod>(); Mods.Value = firstItem.RequiredMods?.ToArray() ?? Array.Empty<Mod>();
} }
return false; return false;

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

@ -26,11 +26,12 @@ namespace osu.Game.Users
{ {
public class UserPanel : OsuClickableContainer, IHasContextMenu public class UserPanel : OsuClickableContainer, IHasContextMenu
{ {
private readonly User user;
private const float height = 100; private const float height = 100;
private const float content_padding = 10; private const float content_padding = 10;
private const float status_height = 30; private const float status_height = 30;
public readonly User User;
[Resolved(canBeNull: true)] [Resolved(canBeNull: true)]
private OsuColour colours { get; set; } private OsuColour colours { get; set; }
@ -54,7 +55,7 @@ namespace osu.Game.Users
if (user == null) if (user == null)
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
this.user = user; User = user;
Height = height - status_height; Height = height - status_height;
} }
@ -86,7 +87,7 @@ namespace osu.Game.Users
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
User = user, User = User,
}, 300, 5000) }, 300, 5000)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -106,7 +107,7 @@ namespace osu.Game.Users
new UpdateableAvatar new UpdateableAvatar
{ {
Size = new Vector2(height - status_height - content_padding * 2), Size = new Vector2(height - status_height - content_padding * 2),
User = user, User = User,
Masking = true, Masking = true,
CornerRadius = 5, CornerRadius = 5,
OpenOnClick = { Value = false }, OpenOnClick = { Value = false },
@ -125,7 +126,7 @@ namespace osu.Game.Users
{ {
new OsuSpriteText new OsuSpriteText
{ {
Text = user.Username, Text = User.Username,
Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 18, italics: true), Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 18, italics: true),
}, },
infoContainer = new FillFlowContainer infoContainer = new FillFlowContainer
@ -138,7 +139,7 @@ namespace osu.Game.Users
Spacing = new Vector2(5f, 0f), Spacing = new Vector2(5f, 0f),
Children = new Drawable[] Children = new Drawable[]
{ {
new UpdateableFlag(user.Country) new UpdateableFlag(User.Country)
{ {
Width = 30f, Width = 30f,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
@ -191,12 +192,12 @@ namespace osu.Game.Users
} }
}); });
if (user.IsSupporter) if (User.IsSupporter)
{ {
infoContainer.Add(new SupporterIcon infoContainer.Add(new SupporterIcon
{ {
Height = 20f, Height = 20f,
SupportLevel = user.SupportLevel SupportLevel = User.SupportLevel
}); });
} }
@ -206,7 +207,7 @@ namespace osu.Game.Users
base.Action = ViewProfile = () => base.Action = ViewProfile = () =>
{ {
Action?.Invoke(); Action?.Invoke();
profile?.ShowUser(user); profile?.ShowUser(User);
}; };
} }

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" />