1
0
mirror of https://github.com/ppy/osu.git synced 2026-06-03 17:23:57 +08:00

Isolate operation of multiplayer mod overlay

This commit is contained in:
Dan Balasescu
2025-04-01 14:41:17 +09:00
Unverified
parent 596b7038ba
commit 8de9620156
3 changed files with 111 additions and 59 deletions
@@ -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;
/// <summary>
/// Any mods applied by/to the local user.
/// </summary>
protected readonly Bindable<IReadOnlyList<Mod>> UserMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
[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<Mod>().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)!;
@@ -0,0 +1,108 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using 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<IReadOnlyList<Mod>> 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<Mod>().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();
}
}
}
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using 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<IReadOnlyList<Mod>> 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<BeatmapAvailability> 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