diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
index 57e8aff151..c73a36617d 100644
--- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using osu.Framework.Allocation;
@@ -27,6 +26,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
+using osu.Game.Screens.OnlinePlay.Multiplayer.Match;
using osu.Game.Utils;
using Container = osu.Framework.Graphics.Containers.Container;
@@ -62,11 +62,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
private Sample? sampleStart;
- ///
- /// Any mods applied by/to the local user.
- ///
- protected readonly Bindable> UserMods = new Bindable>(Array.Empty());
-
[Resolved(CanBeNull = true)]
private IOverlayManager? overlayManager { get; set; }
@@ -245,12 +240,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
}
};
- LoadComponent(UserModsSelectOverlay = new RoomModSelectOverlay
- {
- SelectedItem = { BindTarget = SelectedItem },
- SelectedMods = { BindTarget = UserMods },
- IsValidMod = _ => false
- });
+ LoadComponent(UserModsSelectOverlay = new MultiplayerUserModSelectOverlay());
}
protected override void LoadComplete()
@@ -258,7 +248,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
base.LoadComplete();
SelectedItem.BindValueChanged(_ => updateSpecifics());
- UserMods.BindValueChanged(_ => updateSpecifics());
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => updateSpecifics());
@@ -441,11 +430,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
? rulesetInstance.AllMods.OfType().Where(m => ModUtils.IsValidFreeModForMatchType(m, Room.Type)).ToArray()
: item.AllowedMods.Select(m => m.ToMod(rulesetInstance)).ToArray();
- // Remove any user mods that are no longer allowed.
- Mod[] newUserMods = UserMods.Value.Where(m => allowedMods.Any(a => m.GetType() == a.GetType())).ToArray();
- if (!newUserMods.SequenceEqual(UserMods.Value))
- UserMods.Value = newUserMods;
-
// Retrieve the corresponding local beatmap, since we can't directly use the playlist's beatmap info
int beatmapId = GetGameplayBeatmap().OnlineID;
var localBeatmap = beatmapManager.QueryBeatmap($@"{nameof(BeatmapInfo.OnlineID)} == $0 AND {nameof(BeatmapInfo.MD5Hash)} == {nameof(BeatmapInfo.OnlineMD5Hash)}", beatmapId);
@@ -456,15 +440,11 @@ namespace osu.Game.Screens.OnlinePlay.Match
Ruleset.Value = GetGameplayRuleset();
if (allowedMods.Length > 0)
- {
UserModsSection.Show();
- UserModsSelectOverlay.IsValidMod = m => allowedMods.Any(a => a.GetType() == m.GetType());
- }
else
{
UserModsSection.Hide();
UserModsSelectOverlay.Hide();
- UserModsSelectOverlay.IsValidMod = _ => false;
}
if (item.Freestyle)
@@ -488,7 +468,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
UserStyleSection.Hide();
}
- protected virtual APIMod[] GetGameplayMods() => UserMods.Value.Select(m => new APIMod(m)).Concat(SelectedItem.Value!.RequiredMods).ToArray();
+ protected virtual APIMod[] GetGameplayMods() => SelectedItem.Value!.RequiredMods;
protected virtual RulesetInfo GetGameplayRuleset() => Rulesets.GetRuleset(SelectedItem.Value!.RulesetID)!;
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerUserModSelectOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerUserModSelectOverlay.cs
new file mode 100644
index 0000000000..e5c447f038
--- /dev/null
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerUserModSelectOverlay.cs
@@ -0,0 +1,108 @@
+// 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.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Extensions.ObjectExtensions;
+using osu.Framework.Threading;
+using osu.Game.Configuration;
+using osu.Game.Online.Multiplayer;
+using osu.Game.Online.Rooms;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Screens.OnlinePlay.Match;
+using osu.Game.Utils;
+
+namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
+{
+ public class MultiplayerUserModSelectOverlay : RoomModSelectOverlay
+ {
+ [Resolved]
+ private MultiplayerClient client { get; set; } = null!;
+
+ [Resolved]
+ private RulesetStore rulesets { get; set; } = null!;
+
+ private ModSettingChangeTracker? modSettingChangeTracker;
+ private ScheduledDelegate? debouncedModSettingsUpdate;
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ IsValidMod = _ => false;
+
+ client.RoomUpdated += onRoomUpdated;
+
+ SelectedItem.BindValueChanged(_ => updateSpecifics());
+ SelectedMods.BindValueChanged(_ => updateSpecifics());
+ SelectedMods.BindValueChanged(onSelectedModsChanged);
+ }
+
+ private void onRoomUpdated()
+ {
+ if (client.Room == null)
+ return;
+
+ SelectedItem.Value = new PlaylistItem(client.Room.CurrentPlaylistItem);
+ }
+
+ private void onSelectedModsChanged(ValueChangedEvent> mods)
+ {
+ modSettingChangeTracker?.Dispose();
+
+ if (client.Room == null)
+ return;
+
+ client.ChangeUserMods(mods.NewValue).FireAndForget();
+
+ modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue);
+ modSettingChangeTracker.SettingChanged += _ =>
+ {
+ // Debounce changes to mod settings so as to not thrash the network.
+ debouncedModSettingsUpdate?.Cancel();
+ debouncedModSettingsUpdate = Scheduler.AddDelayed(() =>
+ {
+ if (client.Room == null)
+ return;
+
+ client.ChangeUserMods(SelectedMods.Value).FireAndForget();
+ }, 500);
+ };
+ }
+
+ private void updateSpecifics()
+ {
+ if (client.Room == null || client.LocalUser == null)
+ return;
+
+ MultiplayerPlaylistItem currentItem = client.Room.CurrentPlaylistItem;
+ Ruleset ruleset = rulesets.GetRuleset(client.LocalUser.RulesetId ?? currentItem.RulesetID)!.CreateInstance();
+ Mod[] allowedMods = currentItem.Freestyle
+ ? ruleset.AllMods.OfType().Where(m => ModUtils.IsValidFreeModForMatchType(m, client.Room.Settings.MatchType)).ToArray()
+ : currentItem.AllowedMods.Select(m => m.ToMod(ruleset)).ToArray();
+
+ // Update the mod panels to reflect the ones which are valid for selection.
+ IsValidMod = allowedMods.Length > 0
+ ? m => allowedMods.Any(a => a.GetType() == m.GetType())
+ : _ => false;
+
+ // Remove any mods that are no longer allowed.
+ Mod[] newUserMods = SelectedMods.Value.Where(m => allowedMods.Any(a => m.GetType() == a.GetType())).ToArray();
+ if (!newUserMods.SequenceEqual(SelectedMods.Value))
+ SelectedMods.Value = newUserMods;
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (client.IsNotNull())
+ client.RoomUpdated -= onRoomUpdated;
+
+ modSettingChangeTracker?.Dispose();
+ }
+ }
+}
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs
index 08a469fa03..0cc033907f 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs
@@ -1,7 +1,6 @@
// 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.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
@@ -11,9 +10,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Framework.Screens;
-using osu.Framework.Threading;
using osu.Game.Beatmaps;
-using osu.Game.Configuration;
using osu.Game.Graphics.Cursor;
using osu.Game.Online;
using osu.Game.Online.API;
@@ -23,7 +20,6 @@ using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
using osu.Game.Rulesets;
-using osu.Game.Rulesets.Mods;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Screens.OnlinePlay.Match.Components;
@@ -64,7 +60,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
base.LoadComplete();
BeatmapAvailability.BindValueChanged(updateBeatmapAvailability, true);
- UserMods.BindValueChanged(onUserModsChanged);
client.LoadRequested += onLoadRequested;
client.RoomUpdated += onRoomUpdated;
@@ -306,35 +301,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
protected override void PartRoom() => client.LeaveRoom();
- private ModSettingChangeTracker? modSettingChangeTracker;
- private ScheduledDelegate? debouncedModSettingsUpdate;
-
- private void onUserModsChanged(ValueChangedEvent> mods)
- {
- modSettingChangeTracker?.Dispose();
-
- if (client.Room == null)
- return;
-
- client.ChangeUserMods(mods.NewValue).FireAndForget();
-
- modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue);
- modSettingChangeTracker.SettingChanged += onModSettingsChanged;
- }
-
- private void onModSettingsChanged(Mod mod)
- {
- // Debounce changes to mod settings so as to not thrash the network.
- debouncedModSettingsUpdate?.Cancel();
- debouncedModSettingsUpdate = Scheduler.AddDelayed(() =>
- {
- if (client.Room == null)
- return;
-
- client.ChangeUserMods(UserMods.Value).FireAndForget();
- }, 500);
- }
-
private void updateBeatmapAvailability(ValueChangedEvent availability)
{
if (client.Room == null)
@@ -462,8 +428,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
client.RoomUpdated -= onRoomUpdated;
client.LoadRequested -= onLoadRequested;
}
-
- modSettingChangeTracker?.Dispose();
}
public partial class AddItemButton : PurpleRoundedButton