diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
index 5fd8b8b337..ff147aba10 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
@@ -202,7 +202,7 @@ namespace osu.Game.Online.Multiplayer
Debug.Assert(joinedRoom.Playlist.Count > 0);
APIRoom.Playlist.Clear();
- APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(createPlaylistItem));
+ APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(item => new PlaylistItem(item)));
APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == joinedRoom.Settings.PlaylistItemId);
// The server will null out the end date upon the host joining the room, but the null value is never communicated to the client.
@@ -734,7 +734,7 @@ namespace osu.Game.Online.Multiplayer
Debug.Assert(APIRoom != null);
Room.Playlist.Add(item);
- APIRoom.Playlist.Add(createPlaylistItem(item));
+ APIRoom.Playlist.Add(new PlaylistItem(item));
ItemAdded?.Invoke(item);
RoomUpdated?.Invoke();
@@ -780,7 +780,7 @@ namespace osu.Game.Online.Multiplayer
int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID));
APIRoom.Playlist.RemoveAt(existingIndex);
- APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item));
+ APIRoom.Playlist.Insert(existingIndex, new PlaylistItem(item));
}
catch (Exception ex)
{
@@ -853,18 +853,6 @@ namespace osu.Game.Online.Multiplayer
RoomUpdated?.Invoke();
}
- private PlaylistItem createPlaylistItem(MultiplayerPlaylistItem item) => new PlaylistItem(new APIBeatmap { OnlineID = item.BeatmapID, StarRating = item.StarRating })
- {
- ID = item.ID,
- OwnerID = item.OwnerID,
- RulesetID = item.RulesetID,
- Expired = item.Expired,
- PlaylistOrder = item.PlaylistOrder,
- PlayedAt = item.PlayedAt,
- RequiredMods = item.RequiredMods.ToArray(),
- AllowedMods = item.AllowedMods.ToArray()
- };
-
///
/// For the provided user ID, update whether the user is included in .
///
diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomExtensions.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomExtensions.cs
new file mode 100644
index 0000000000..0aeb85d2d8
--- /dev/null
+++ b/osu.Game/Online/Multiplayer/MultiplayerRoomExtensions.cs
@@ -0,0 +1,39 @@
+// 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 osu.Game.Online.Rooms;
+
+namespace osu.Game.Online.Multiplayer
+{
+ public static class MultiplayerRoomExtensions
+ {
+ ///
+ /// Returns all historical/expired items from the , in the order in which they were played.
+ ///
+ public static IEnumerable GetHistoricalItems(this MultiplayerRoom room)
+ => room.Playlist.Where(item => item.Expired).OrderBy(item => item.PlayedAt);
+
+ ///
+ /// Returns all non-expired items from the , in the order in which they are to be played.
+ ///
+ public static IEnumerable GetUpcomingItems(this MultiplayerRoom room)
+ => room.Playlist.Where(item => !item.Expired).OrderBy(item => item.PlaylistOrder);
+
+ ///
+ /// Returns the first non-expired in playlist order from the supplied ,
+ /// or the last-played if all items are expired,
+ /// or if was empty.
+ ///
+ public static MultiplayerPlaylistItem? GetCurrentItem(this MultiplayerRoom room)
+ {
+ if (room.Playlist.Count == 0)
+ return null;
+
+ return room.Playlist.All(item => item.Expired)
+ ? GetHistoricalItems(room).Last()
+ : GetUpcomingItems(room).First();
+ }
+ }
+}
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs
index adfc44fbd4..09aafa415a 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs
@@ -1,23 +1,25 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Game.Screens.OnlinePlay.Multiplayer;
+using osu.Game.Online.Multiplayer;
using osuTK;
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
- public partial class RankRangePill : MultiplayerRoomComposite
+ public partial class RankRangePill : CompositeDrawable
{
- private OsuTextFlowContainer rankFlow;
+ private OsuTextFlowContainer rankFlow = null!;
+
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
public RankRangePill()
{
@@ -55,20 +57,28 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
};
}
- protected override void OnRoomUpdated()
+ protected override void LoadComplete()
{
- base.OnRoomUpdated();
+ base.LoadComplete();
+ client.RoomUpdated += onRoomUpdated;
+ updateState();
+ }
+
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+
+ private void updateState()
+ {
rankFlow.Clear();
- if (Room == null || Room.Users.All(u => u.User == null))
+ if (client.Room == null || client.Room.Users.All(u => u.User == null))
{
rankFlow.AddText("-");
return;
}
- int minRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min();
- int maxRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max();
+ int minRank = client.Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min();
+ int maxRank = client.Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max();
rankFlow.AddText("#");
rankFlow.AddText(minRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold));
@@ -78,5 +88,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
rankFlow.AddText("#");
rankFlow.AddText(maxRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold));
}
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ client.RoomUpdated -= onRoomUpdated;
+ }
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs
index ba3508b24f..a82fa6e4bc 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MatchStartControl.cs
@@ -1,47 +1,50 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Diagnostics;
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Multiplayer.Countdown;
+using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
using osuTK;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
- public partial class MatchStartControl : MultiplayerRoomComposite
+ public partial class MatchStartControl : CompositeDrawable
{
[Resolved]
- private OngoingOperationTracker ongoingOperationTracker { get; set; }
-
- [CanBeNull]
- private IDisposable clickOperation;
+ private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!;
[Resolved(canBeNull: true)]
- private IDialogOverlay dialogOverlay { get; set; }
+ private IDialogOverlay? dialogOverlay { get; set; }
- private Sample sampleReady;
- private Sample sampleReadyAll;
- private Sample sampleUnready;
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
+
+ [Resolved]
+ private IBindable currentItem { get; set; } = null!;
private readonly MultiplayerReadyButton readyButton;
private readonly MultiplayerCountdownButton countdownButton;
+
+ private IBindable operationInProgress = null!;
+ private ScheduledDelegate? readySampleDelegate;
+ private IDisposable? clickOperation;
+ private Sample? sampleReady;
+ private Sample? sampleReadyAll;
+ private Sample? sampleUnready;
private int countReady;
- private ScheduledDelegate readySampleDelegate;
- private IBindable operationInProgress;
public MatchStartControl()
{
@@ -91,34 +94,29 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
base.LoadComplete();
- CurrentPlaylistItem.BindValueChanged(_ => updateState());
- }
-
- protected override void OnRoomUpdated()
- {
- base.OnRoomUpdated();
+ currentItem.BindValueChanged(_ => updateState());
+ client.RoomUpdated += onRoomUpdated;
+ client.LoadRequested += onLoadRequested;
updateState();
}
- protected override void OnRoomLoadRequested()
- {
- base.OnRoomLoadRequested();
- endOperation();
- }
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+
+ private void onLoadRequested() => Scheduler.AddOnce(endOperation);
private void onReadyButtonClick()
{
- if (Room == null)
+ if (client.Room == null)
return;
Debug.Assert(clickOperation == null);
clickOperation = ongoingOperationTracker.BeginOperation();
- if (Client.IsHost)
+ if (client.IsHost)
{
- if (Room.State == MultiplayerRoomState.Open)
+ if (client.Room.State == MultiplayerRoomState.Open)
{
- if (isReady() && !Room.ActiveCountdowns.Any(c => c is MatchStartCountdown))
+ if (isReady() && !client.Room.ActiveCountdowns.Any(c => c is MatchStartCountdown))
startMatch();
else
toggleReady();
@@ -131,16 +129,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
dialogOverlay.Push(new ConfirmAbortDialog(abortMatch, endOperation));
}
}
- else if (Room.State != MultiplayerRoomState.Closed)
+ else if (client.Room.State != MultiplayerRoomState.Closed)
toggleReady();
- bool isReady() => Client.LocalUser?.State == MultiplayerUserState.Ready || Client.LocalUser?.State == MultiplayerUserState.Spectating;
+ bool isReady() => client.LocalUser?.State == MultiplayerUserState.Ready || client.LocalUser?.State == MultiplayerUserState.Spectating;
- void toggleReady() => Client.ToggleReady().FireAndForget(
+ void toggleReady() => client.ToggleReady().FireAndForget(
onSuccess: endOperation,
onError: _ => endOperation());
- void startMatch() => Client.StartMatch().FireAndForget(onSuccess: () =>
+ void startMatch() => client.StartMatch().FireAndForget(onSuccess: () =>
{
// gameplay is starting, the button will be unblocked on load requested.
}, onError: _ =>
@@ -149,7 +147,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
endOperation();
});
- void abortMatch() => Client.AbortMatch().FireAndForget(endOperation, _ => endOperation());
+ void abortMatch() => client.AbortMatch().FireAndForget(endOperation, _ => endOperation());
}
private void startCountdown(TimeSpan duration)
@@ -157,19 +155,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
Debug.Assert(clickOperation == null);
clickOperation = ongoingOperationTracker.BeginOperation();
- Client.SendMatchRequest(new StartMatchCountdownRequest { Duration = duration }).ContinueWith(_ => endOperation());
+ client.SendMatchRequest(new StartMatchCountdownRequest { Duration = duration }).ContinueWith(_ => endOperation());
}
private void cancelCountdown()
{
- if (Client.Room == null)
+ if (client.Room == null)
return;
Debug.Assert(clickOperation == null);
clickOperation = ongoingOperationTracker.BeginOperation();
- MultiplayerCountdown countdown = Client.Room.ActiveCountdowns.Single(c => c is MatchStartCountdown);
- Client.SendMatchRequest(new StopCountdownRequest(countdown.ID)).ContinueWith(_ => endOperation());
+ MultiplayerCountdown countdown = client.Room.ActiveCountdowns.Single(c => c is MatchStartCountdown);
+ client.SendMatchRequest(new StopCountdownRequest(countdown.ID)).ContinueWith(_ => endOperation());
}
private void endOperation()
@@ -180,19 +178,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
private void updateState()
{
- if (Room == null)
+ if (client.Room == null)
{
readyButton.Enabled.Value = false;
countdownButton.Enabled.Value = false;
return;
}
- var localUser = Client.LocalUser;
+ var localUser = client.LocalUser;
- int newCountReady = Room.Users.Count(u => u.State == MultiplayerUserState.Ready);
- int newCountTotal = Room.Users.Count(u => u.State != MultiplayerUserState.Spectating);
+ int newCountReady = client.Room.Users.Count(u => u.State == MultiplayerUserState.Ready);
+ int newCountTotal = client.Room.Users.Count(u => u.State != MultiplayerUserState.Spectating);
- if (!Client.IsHost || Room.Settings.AutoStartEnabled)
+ if (!client.IsHost || client.Room.Settings.AutoStartEnabled)
countdownButton.Hide();
else
{
@@ -211,21 +209,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
}
readyButton.Enabled.Value = countdownButton.Enabled.Value =
- Room.State != MultiplayerRoomState.Closed
- && CurrentPlaylistItem.Value?.ID == Room.Settings.PlaylistItemId
- && !Room.Playlist.Single(i => i.ID == Room.Settings.PlaylistItemId).Expired
+ client.Room.State != MultiplayerRoomState.Closed
+ && currentItem.Value?.ID == client.Room.Settings.PlaylistItemId
+ && !client.Room.Playlist.Single(i => i.ID == client.Room.Settings.PlaylistItemId).Expired
&& !operationInProgress.Value;
// When the local user is the host and spectating the match, the ready button should be enabled only if any users are ready.
if (localUser?.State == MultiplayerUserState.Spectating)
- readyButton.Enabled.Value &= Client.IsHost && newCountReady > 0 && !Room.ActiveCountdowns.Any(c => c is MatchStartCountdown);
+ readyButton.Enabled.Value &= client.IsHost && newCountReady > 0 && !client.Room.ActiveCountdowns.Any(c => c is MatchStartCountdown);
// When the local user is not the host, the button should only be enabled when no match is in progress.
- if (!Client.IsHost)
- readyButton.Enabled.Value &= Room.State == MultiplayerRoomState.Open;
+ if (!client.IsHost)
+ readyButton.Enabled.Value &= client.Room.State == MultiplayerRoomState.Open;
// At all times, the countdown button should only be enabled when no match is in progress.
- countdownButton.Enabled.Value &= Room.State == MultiplayerRoomState.Open;
+ countdownButton.Enabled.Value &= client.Room.State == MultiplayerRoomState.Open;
if (newCountReady == countReady)
return;
@@ -249,6 +247,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
});
}
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ {
+ client.RoomUpdated -= onRoomUpdated;
+ client.LoadRequested -= onLoadRequested;
+ }
+ }
+
public partial class ConfirmAbortDialog : DangerousActionDialog
{
public ConfirmAbortDialog(Action abortMatch, Action cancel)
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs
index ea7ab2dce3..92edc9b979 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerSpectateButton.cs
@@ -5,7 +5,9 @@ using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
@@ -17,7 +19,7 @@ using osuTK;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
- public partial class MultiplayerSpectateButton : MultiplayerRoomComposite
+ public partial class MultiplayerSpectateButton : CompositeDrawable
{
[Resolved]
private OngoingOperationTracker ongoingOperationTracker { get; set; } = null!;
@@ -25,6 +27,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
[Resolved]
private OsuColour colours { get; set; } = null!;
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
+
+ [Resolved]
+ private IBindable currentItem { get; set; } = null!;
+
private IBindable operationInProgress = null!;
private readonly RoundedButton button;
@@ -44,7 +52,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
var clickOperation = ongoingOperationTracker.BeginOperation();
- Client.ToggleSpectate().ContinueWith(_ => endOperation());
+ client.ToggleSpectate().ContinueWith(_ => endOperation());
void endOperation() => clickOperation?.Dispose();
}
@@ -63,19 +71,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
base.LoadComplete();
- CurrentPlaylistItem.BindValueChanged(_ => Scheduler.AddOnce(checkForAutomaticDownload), true);
- }
-
- protected override void OnRoomUpdated()
- {
- base.OnRoomUpdated();
-
+ currentItem.BindValueChanged(_ => Scheduler.AddOnce(checkForAutomaticDownload), true);
+ client.RoomUpdated += onRoomUpdated;
updateState();
}
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+
private void updateState()
{
- switch (Client.LocalUser?.State)
+ switch (client.LocalUser?.State)
{
default:
button.Text = "Spectate";
@@ -88,8 +93,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
break;
}
- button.Enabled.Value = Client.Room != null
- && Client.Room.State != MultiplayerRoomState.Closed
+ button.Enabled.Value = client.Room != null
+ && client.Room.State != MultiplayerRoomState.Closed
&& !operationInProgress.Value;
Scheduler.AddOnce(checkForAutomaticDownload);
@@ -112,11 +117,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
private void checkForAutomaticDownload()
{
- PlaylistItem? currentItem = CurrentPlaylistItem.Value;
+ PlaylistItem? item = currentItem.Value;
downloadCheckCancellation?.Cancel();
- if (currentItem == null)
+ if (item == null)
return;
if (!automaticallyDownload.Value)
@@ -128,13 +133,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
//
// Rather than over-complicating this flow, let's only auto-download when spectating for the time being.
// A potential path forward would be to have a local auto-download checkbox above the playlist item list area.
- if (Client.LocalUser?.State != MultiplayerUserState.Spectating)
+ if (client.LocalUser?.State != MultiplayerUserState.Spectating)
return;
// In a perfect world we'd use BeatmapAvailability, but there's no event-driven flow for when a selection changes.
// ie. if selection changes from "not downloaded" to another "not downloaded" we wouldn't get a value changed raised.
beatmapLookupCache
- .GetBeatmapAsync(currentItem.Beatmap.OnlineID, (downloadCheckCancellation = new CancellationTokenSource()).Token)
+ .GetBeatmapAsync(item.Beatmap.OnlineID, (downloadCheckCancellation = new CancellationTokenSource()).Token)
.ContinueWith(resolved => Schedule(() =>
{
var beatmapSet = resolved.GetResultSafely()?.BeatmapSet;
@@ -150,5 +155,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
}
#endregion
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ client.RoomUpdated -= onRoomUpdated;
+ }
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs
index 2d08d8ecf6..8ba85019d5 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/Playlist/MultiplayerPlaylist.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Allocation;
@@ -17,18 +15,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
///
/// The multiplayer playlist, containing lists to show the items from a in both gameplay-order and historical-order.
///
- public partial class MultiplayerPlaylist : MultiplayerRoomComposite
+ public partial class MultiplayerPlaylist : CompositeDrawable
{
public readonly Bindable DisplayMode = new Bindable();
///
/// Invoked when an item requests to be edited.
///
- public Action RequestEdit;
+ public Action? RequestEdit;
- private MultiplayerPlaylistTabControl playlistTabControl;
- private MultiplayerQueueList queueList;
- private MultiplayerHistoryList historyList;
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
+
+ [Resolved]
+ private IBindable currentItem { get; set; } = null!;
+
+ private MultiplayerPlaylistTabControl playlistTabControl = null!;
+ private MultiplayerQueueList queueList = null!;
+ private MultiplayerHistoryList historyList = null!;
private bool firstPopulation = true;
[BackgroundDependencyLoader]
@@ -54,14 +58,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
queueList = new MultiplayerQueueList
{
RelativeSizeAxes = Axes.Both,
- SelectedItem = { BindTarget = CurrentPlaylistItem },
+ SelectedItem = { BindTarget = currentItem },
RequestEdit = item => RequestEdit?.Invoke(item)
},
historyList = new MultiplayerHistoryList
{
RelativeSizeAxes = Axes.Both,
Alpha = 0,
- SelectedItem = { BindTarget = CurrentPlaylistItem }
+ SelectedItem = { BindTarget = currentItem }
}
}
}
@@ -73,7 +77,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
protected override void LoadComplete()
{
base.LoadComplete();
+
DisplayMode.BindValueChanged(onDisplayModeChanged, true);
+ client.ItemAdded += playlistItemAdded;
+ client.ItemRemoved += playlistItemRemoved;
+ client.ItemChanged += playlistItemChanged;
+ client.RoomUpdated += onRoomUpdated;
+ updateState();
}
private void onDisplayModeChanged(ValueChangedEvent mode)
@@ -82,11 +92,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
queueList.FadeTo(mode.NewValue == MultiplayerPlaylistDisplayMode.Queue ? 1 : 0, 100);
}
- protected override void OnRoomUpdated()
- {
- base.OnRoomUpdated();
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
- if (Room == null)
+ private void updateState()
+ {
+ if (client.Room == null)
{
historyList.Items.Clear();
queueList.Items.Clear();
@@ -96,34 +106,27 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
if (firstPopulation)
{
- foreach (var item in Room.Playlist)
+ foreach (var item in client.Room.Playlist)
addItemToLists(item);
firstPopulation = false;
}
}
- protected override void PlaylistItemAdded(MultiplayerPlaylistItem item)
- {
- base.PlaylistItemAdded(item);
- addItemToLists(item);
- }
+ private void playlistItemAdded(MultiplayerPlaylistItem item) => Schedule(() => addItemToLists(item));
- protected override void PlaylistItemRemoved(long item)
- {
- base.PlaylistItemRemoved(item);
- removeItemFromLists(item);
- }
+ private void playlistItemRemoved(long item) => Schedule(() => removeItemFromLists(item));
- protected override void PlaylistItemChanged(MultiplayerPlaylistItem item)
+ private void playlistItemChanged(MultiplayerPlaylistItem item) => Schedule(() =>
{
- base.PlaylistItemChanged(item);
+ if (client.Room == null)
+ return;
- var newApiItem = Playlist.SingleOrDefault(i => i.ID == item.ID);
+ var newApiItem = new PlaylistItem(item);
var existingApiItemInQueue = queueList.Items.SingleOrDefault(i => i.ID == item.ID);
// Test if the only change between the two playlist items is the order.
- if (newApiItem != null && existingApiItemInQueue != null && existingApiItemInQueue.With(playlistOrder: newApiItem.PlaylistOrder).Equals(newApiItem))
+ if (existingApiItemInQueue != null && existingApiItemInQueue.With(playlistOrder: newApiItem.PlaylistOrder).Equals(newApiItem))
{
// Set the new playlist order directly without refreshing the DrawablePlaylistItem.
existingApiItemInQueue.PlaylistOrder = newApiItem.PlaylistOrder;
@@ -137,20 +140,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match.Playlist
removeItemFromLists(item.ID);
addItemToLists(item);
}
- }
+ });
private void addItemToLists(MultiplayerPlaylistItem item)
{
- var apiItem = Playlist.SingleOrDefault(i => i.ID == item.ID);
+ var apiItem = client.Room?.Playlist.SingleOrDefault(i => i.ID == item.ID);
// Item could have been removed from the playlist while the local player was in gameplay.
if (apiItem == null)
return;
if (item.Expired)
- historyList.Items.Add(apiItem);
+ historyList.Items.Add(new PlaylistItem(apiItem));
else
- queueList.Items.Add(apiItem);
+ queueList.Items.Add(new PlaylistItem(apiItem));
}
private void removeItemFromLists(long item)
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs
deleted file mode 100644
index ee5c84bf40..0000000000
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-#nullable disable
-
-using JetBrains.Annotations;
-using osu.Framework.Allocation;
-using osu.Game.Online.Multiplayer;
-using osu.Game.Online.Rooms;
-
-namespace osu.Game.Screens.OnlinePlay.Multiplayer
-{
- public abstract partial class MultiplayerRoomComposite : OnlinePlayComposite
- {
- [CanBeNull]
- protected MultiplayerRoom Room => Client.Room;
-
- [Resolved]
- protected MultiplayerClient Client { get; private set; }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- Client.RoomUpdated += invokeOnRoomUpdated;
- Client.LoadRequested += invokeOnRoomLoadRequested;
- Client.UserLeft += invokeUserLeft;
- Client.UserKicked += invokeUserKicked;
- Client.UserJoined += invokeUserJoined;
- Client.ItemAdded += invokeItemAdded;
- Client.ItemRemoved += invokeItemRemoved;
- Client.ItemChanged += invokeItemChanged;
-
- OnRoomUpdated();
- }
-
- private void invokeOnRoomUpdated() => Scheduler.AddOnce(OnRoomUpdated);
- private void invokeUserJoined(MultiplayerRoomUser user) => Scheduler.Add(() => UserJoined(user));
- private void invokeUserKicked(MultiplayerRoomUser user) => Scheduler.Add(() => UserKicked(user));
- private void invokeUserLeft(MultiplayerRoomUser user) => Scheduler.Add(() => UserLeft(user));
- private void invokeItemAdded(MultiplayerPlaylistItem item) => Schedule(() => PlaylistItemAdded(item));
- private void invokeItemRemoved(long item) => Schedule(() => PlaylistItemRemoved(item));
- private void invokeItemChanged(MultiplayerPlaylistItem item) => Schedule(() => PlaylistItemChanged(item));
- private void invokeOnRoomLoadRequested() => Scheduler.AddOnce(OnRoomLoadRequested);
-
- ///
- /// Invoked when a user has joined the room.
- ///
- /// The user.
- protected virtual void UserJoined(MultiplayerRoomUser user)
- {
- }
-
- ///
- /// Invoked when a user has been kicked from the room (including the local user).
- ///
- /// The user.
- protected virtual void UserKicked(MultiplayerRoomUser user)
- {
- }
-
- ///
- /// Invoked when a user has left the room.
- ///
- /// The user.
- protected virtual void UserLeft(MultiplayerRoomUser user)
- {
- }
-
- ///
- /// Invoked when a playlist item is added to the room.
- ///
- /// The added playlist item.
- protected virtual void PlaylistItemAdded(MultiplayerPlaylistItem item)
- {
- }
-
- ///
- /// Invoked when a playlist item is removed from the room.
- ///
- /// The ID of the removed playlist item.
- protected virtual void PlaylistItemRemoved(long item)
- {
- }
-
- ///
- /// Invoked when a playlist item is changed in the room.
- ///
- /// The new playlist item, with an existing item's ID.
- protected virtual void PlaylistItemChanged(MultiplayerPlaylistItem item)
- {
- }
-
- ///
- /// Invoked when any change occurs to the multiplayer room.
- ///
- protected virtual void OnRoomUpdated()
- {
- }
-
- ///
- /// Invoked when the room requests the local user to load into gameplay.
- ///
- protected virtual void OnRoomLoadRequested()
- {
- }
-
- protected override void Dispose(bool isDisposing)
- {
- if (Client != null)
- {
- Client.RoomUpdated -= invokeOnRoomUpdated;
- Client.LoadRequested -= invokeOnRoomLoadRequested;
- Client.UserLeft -= invokeUserLeft;
- Client.UserKicked -= invokeUserKicked;
- Client.UserJoined -= invokeUserJoined;
- Client.ItemAdded -= invokeItemAdded;
- Client.ItemRemoved -= invokeItemRemoved;
- Client.ItemChanged -= invokeItemChanged;
- }
-
- base.Dispose(isDisposing);
- }
- }
-}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs
index 90595bc33b..d53e485c86 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomSounds.cs
@@ -1,23 +1,26 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
+using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
-using osu.Framework.Bindables;
-using osu.Game.Online.API.Requests.Responses;
+using osu.Framework.Extensions.ObjectExtensions;
+using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
- public partial class MultiplayerRoomSounds : MultiplayerRoomComposite
+ public partial class MultiplayerRoomSounds : CompositeDrawable
{
- private Sample hostChangedSample;
- private Sample userJoinedSample;
- private Sample userLeftSample;
- private Sample userKickedSample;
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
+
+ private Sample? hostChangedSample;
+ private Sample? userJoinedSample;
+ private Sample? userLeftSample;
+ private Sample? userKickedSample;
+ private MultiplayerRoomUser? host;
[BackgroundDependencyLoader]
private void load(AudioManager audio)
@@ -32,36 +35,47 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
base.LoadComplete();
- Host.BindValueChanged(hostChanged);
+ client.RoomUpdated += onRoomUpdated;
+ client.UserJoined += onUserJoined;
+ client.UserLeft += onUserLeft;
+ client.UserKicked += onUserKicked;
+ updateState();
}
- protected override void UserJoined(MultiplayerRoomUser user)
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+
+ private void updateState()
{
- base.UserJoined(user);
+ if (EqualityComparer.Default.Equals(host, client.Room?.Host))
+ return;
- Scheduler.AddOnce(() => userJoinedSample?.Play());
- }
-
- protected override void UserLeft(MultiplayerRoomUser user)
- {
- base.UserLeft(user);
-
- Scheduler.AddOnce(() => userLeftSample?.Play());
- }
-
- protected override void UserKicked(MultiplayerRoomUser user)
- {
- base.UserKicked(user);
-
- Scheduler.AddOnce(() => userKickedSample?.Play());
- }
-
- private void hostChanged(ValueChangedEvent value)
- {
// only play sound when the host changes from an already-existing host.
- if (value.OldValue == null) return;
+ if (host != null)
+ Scheduler.AddOnce(() => hostChangedSample?.Play());
- Scheduler.AddOnce(() => hostChangedSample?.Play());
+ host = client.Room?.Host;
+ }
+
+ private void onUserJoined(MultiplayerRoomUser user)
+ => Scheduler.AddOnce(() => userJoinedSample?.Play());
+
+ private void onUserLeft(MultiplayerRoomUser user)
+ => Scheduler.AddOnce(() => userLeftSample?.Play());
+
+ private void onUserKicked(MultiplayerRoomUser user)
+ => Scheduler.AddOnce(() => userKickedSample?.Play());
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ {
+ client.RoomUpdated -= onRoomUpdated;
+ client.UserJoined -= onUserJoined;
+ client.UserLeft -= onUserLeft;
+ client.UserKicked -= onUserKicked;
+ }
}
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs
index c79c210e30..7e42b18240 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -30,7 +31,7 @@ using osuTK.Graphics;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
{
- public partial class ParticipantPanel : MultiplayerRoomComposite, IHasContextMenu
+ public partial class ParticipantPanel : CompositeDrawable, IHasContextMenu
{
public readonly MultiplayerRoomUser User;
@@ -40,6 +41,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
[Resolved]
private IRulesetStore rulesets { get; set; } = null!;
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
+
private SpriteIcon crown = null!;
private OsuSpriteText userRankText = null!;
@@ -171,23 +175,31 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
Origin = Anchor.Centre,
Alpha = 0,
Margin = new MarginPadding(4),
- Action = () => Client.KickUser(User.UserID).FireAndForget(),
+ Action = () => client.KickUser(User.UserID).FireAndForget(),
},
},
}
};
}
- protected override void OnRoomUpdated()
+ protected override void LoadComplete()
{
- base.OnRoomUpdated();
+ base.LoadComplete();
- if (Room == null || Client.LocalUser == null)
+ client.RoomUpdated += onRoomUpdated;
+ updateState();
+ }
+
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+
+ private void updateState()
+ {
+ if (client.Room == null || client.LocalUser == null)
return;
const double fade_time = 50;
- var currentItem = Playlist.GetCurrentItem();
+ MultiplayerPlaylistItem? currentItem = client.Room.GetCurrentItem();
Ruleset? ruleset = currentItem != null ? rulesets.GetRuleset(currentItem.RulesetID)?.CreateInstance() : null;
int? currentModeRank = ruleset != null ? User.User?.RulesetsStatistics?.GetValueOrDefault(ruleset.ShortName)?.GlobalRank : null;
@@ -200,8 +212,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
else
userModsDisplay.FadeOut(fade_time);
- kickButton.Alpha = Client.IsHost && !User.Equals(Client.LocalUser) ? 1 : 0;
- crown.Alpha = Room.Host?.Equals(User) == true ? 1 : 0;
+ kickButton.Alpha = client.IsHost && !User.Equals(client.LocalUser) ? 1 : 0;
+ crown.Alpha = client.Room.Host?.Equals(User) == true ? 1 : 0;
// If the mods are updated at the end of the frame, the flow container will skip a reflow cycle: https://github.com/ppy/osu-framework/issues/4187
// This looks particularly jarring here, so re-schedule the update to that start of our frame as a fix.
@@ -215,7 +227,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
{
get
{
- if (Room == null)
+ if (client.Room == null)
return null;
// If the local user is targetted.
@@ -223,7 +235,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
return null;
// If the local user is not the host of the room.
- if (Room.Host?.UserID != api.LocalUser.Value.Id)
+ if (client.Room.Host?.UserID != api.LocalUser.Value.Id)
return null;
int targetUser = User.UserID;
@@ -233,23 +245,31 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
new OsuMenuItem("Give host", MenuItemType.Standard, () =>
{
// Ensure the local user is still host.
- if (!Client.IsHost)
+ if (!client.IsHost)
return;
- Client.TransferHost(targetUser).FireAndForget();
+ client.TransferHost(targetUser).FireAndForget();
}),
new OsuMenuItem("Kick", MenuItemType.Destructive, () =>
{
// Ensure the local user is still host.
- if (!Client.IsHost)
+ if (!client.IsHost)
return;
- Client.KickUser(targetUser).FireAndForget();
+ client.KickUser(targetUser).FireAndForget();
})
};
}
}
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ client.RoomUpdated -= onRoomUpdated;
+ }
+
public partial class KickButton : IconButton
{
public KickButton()
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs
index 6a7a3758c3..a9d7f4ab52 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs
@@ -1,24 +1,24 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
-using JetBrains.Annotations;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
+using osu.Game.Online.Multiplayer;
using osuTK;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
{
- public partial class ParticipantsList : MultiplayerRoomComposite
+ public partial class ParticipantsList : CompositeDrawable
{
- private FillFlowContainer panels;
+ private FillFlowContainer panels = null!;
+ private ParticipantPanel? currentHostPanel;
- [CanBeNull]
- private ParticipantPanel currentHostPanel;
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
[BackgroundDependencyLoader]
private void load()
@@ -37,11 +37,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
};
}
- protected override void OnRoomUpdated()
+ protected override void LoadComplete()
{
- base.OnRoomUpdated();
+ base.LoadComplete();
- if (Room == null)
+ client.RoomUpdated += onRoomUpdated;
+ updateState();
+ }
+
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+
+ private void updateState()
+ {
+ if (client.Room == null)
panels.Clear();
else
{
@@ -49,15 +57,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
foreach (var p in panels)
{
// Note that we *must* use reference equality here, as this call is scheduled and a user may have left and joined since it was last run.
- if (Room.Users.All(u => !ReferenceEquals(p.User, u)))
+ if (client.Room.Users.All(u => !ReferenceEquals(p.User, u)))
p.Expire();
}
// Add panels for all users new to the room.
- foreach (var user in Room.Users.Except(panels.Select(p => p.User)))
+ foreach (var user in client.Room.Users.Except(panels.Select(p => p.User)))
panels.Add(new ParticipantPanel(user));
- if (currentHostPanel == null || !currentHostPanel.User.Equals(Room.Host))
+ if (currentHostPanel == null || !currentHostPanel.User.Equals(client.Room.Host))
{
// Reset position of previous host back to normal, if one existing.
if (currentHostPanel != null && panels.Contains(currentHostPanel))
@@ -66,9 +74,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
currentHostPanel = null;
// Change position of new host to display above all participants.
- if (Room.Host != null)
+ if (client.Room.Host != null)
{
- currentHostPanel = panels.SingleOrDefault(u => u.User.Equals(Room.Host));
+ currentHostPanel = panels.SingleOrDefault(u => u.User.Equals(client.Room.Host));
if (currentHostPanel != null)
panels.SetLayoutPosition(currentHostPanel, -1);
@@ -76,5 +84,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
}
}
}
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ client.RoomUpdated -= onRoomUpdated;
+ }
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs
index fe57ad26a5..bd9511d50d 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs
@@ -1,12 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -20,27 +19,26 @@ using osuTK.Graphics;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
{
- internal partial class TeamDisplay : MultiplayerRoomComposite
+ internal partial class TeamDisplay : CompositeDrawable
{
private readonly MultiplayerRoomUser user;
- private Drawable box;
-
- private Sample sampleTeamSwap;
+ [Resolved]
+ private OsuColour colours { get; set; } = null!;
[Resolved]
- private OsuColour colours { get; set; }
+ private MultiplayerClient client { get; set; } = null!;
- private OsuClickableContainer clickableContent;
+ private OsuClickableContainer clickableContent = null!;
+ private Drawable box = null!;
+ private Sample? sampleTeamSwap;
public TeamDisplay(MultiplayerRoomUser user)
{
this.user = user;
RelativeSizeAxes = Axes.Y;
-
AutoSizeAxes = Axes.X;
-
Margin = new MarginPadding { Horizontal = 3 };
}
@@ -71,7 +69,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
}
};
- if (Client.LocalUser?.Equals(user) == true)
+ if (client.LocalUser?.Equals(user) == true)
{
clickableContent.Action = changeTeam;
clickableContent.TooltipText = "Change team";
@@ -80,23 +78,31 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
sampleTeamSwap = audio.Samples.Get(@"Multiplayer/team-swap");
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ client.RoomUpdated += onRoomUpdated;
+ updateState();
+ }
+
private void changeTeam()
{
- Client.SendMatchRequest(new ChangeTeamRequest
+ client.SendMatchRequest(new ChangeTeamRequest
{
- TeamID = ((Client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0,
+ TeamID = ((client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0,
}).FireAndForget();
}
public int? DisplayedTeam { get; private set; }
- protected override void OnRoomUpdated()
- {
- base.OnRoomUpdated();
+ private void onRoomUpdated() => Scheduler.AddOnce(updateState);
+ private void updateState()
+ {
// we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now.
- var userRoomState = Room?.Users.FirstOrDefault(u => u.Equals(user))?.MatchState;
+ var userRoomState = client.Room?.Users.FirstOrDefault(u => u.Equals(user))?.MatchState;
const double duration = 400;
@@ -138,5 +144,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants
return colours.Blue;
}
}
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ client.RoomUpdated -= onRoomUpdated;
+ }
}
}