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

Merge pull request #11725 from smoogipoo/freemods-user-settings

Add local user customisation for freemod mod settings
This commit is contained in:
Dean Herbert 2021-02-11 16:02:24 +09:00 committed by GitHub
commit 98c5b0220c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 100 additions and 29 deletions

View File

@ -0,0 +1,52 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Configuration
{
/// <summary>
/// A helper class for tracking changes to the settings of a set of <see cref="Mod"/>s.
/// </summary>
/// <remarks>
/// Ensure to dispose when usage is finished.
/// </remarks>
public class ModSettingChangeTracker : IDisposable
{
/// <summary>
/// Notifies that the setting of a <see cref="Mod"/> has changed.
/// </summary>
public Action<Mod> SettingChanged;
private readonly List<ISettingsItem> settings = new List<ISettingsItem>();
/// <summary>
/// Creates a new <see cref="ModSettingChangeTracker"/> for a set of <see cref="Mod"/>s.
/// </summary>
/// <param name="mods">The set of <see cref="Mod"/>s whose settings need to be tracked.</param>
public ModSettingChangeTracker(IEnumerable<Mod> mods)
{
foreach (var mod in mods)
{
foreach (var setting in mod.CreateSettingsControls().OfType<ISettingsItem>())
{
setting.SettingChanged += () => SettingChanged?.Invoke(mod);
settings.Add(setting);
}
}
}
public void Dispose()
{
SettingChanged = null;
foreach (var r in settings)
r.Dispose();
settings.Clear();
}
}
}

View File

@ -51,6 +51,11 @@ namespace osu.Game.Overlays.Mods
/// </summary>
protected virtual bool Stacked => true;
/// <summary>
/// Whether configurable <see cref="Mod"/>s can be configured by the local user.
/// </summary>
protected virtual bool AllowConfiguration => true;
[NotNull]
private Func<Mod, bool> isValidMod = m => true;
@ -300,6 +305,7 @@ namespace osu.Game.Overlays.Mods
Text = "Customisation",
Action = () => ModSettingsContainer.ToggleVisibility(),
Enabled = { Value = false },
Alpha = AllowConfiguration ? 1 : 0,
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
@ -512,7 +518,8 @@ namespace osu.Game.Overlays.Mods
OnModSelected(selectedMod);
if (selectedMod.RequiresConfiguration) ModSettingsContainer.Show();
if (selectedMod.RequiresConfiguration && AllowConfiguration)
ModSettingsContainer.Show();
}
else
{

View File

@ -20,17 +20,18 @@ namespace osu.Game.Screens.OnlinePlay
{
protected override bool Stacked => false;
protected override bool AllowConfiguration => false;
public new Func<Mod, bool> IsValidMod
{
get => base.IsValidMod;
set => base.IsValidMod = m => m.HasImplementation && !m.RequiresConfiguration && !(m is ModAutoplay) && value(m);
set => base.IsValidMod = m => m.HasImplementation && !(m is ModAutoplay) && value(m);
}
public FreeModSelectOverlay()
{
IsValidMod = m => true;
CustomiseButton.Alpha = 0;
MultiplierSection.Alpha = 0;
DeselectAllButton.Alpha = 0;

View File

@ -59,6 +59,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea();
protected override bool IsValidFreeMod(Mod mod) => base.IsValidFreeMod(mod) && !(mod is ModTimeRamp) && !(mod is ModRateAdjust) && !mod.RequiresConfiguration;
protected override bool IsValidFreeMod(Mod mod) => base.IsValidFreeMod(mod) && !(mod is ModTimeRamp) && !(mod is ModRateAdjust);
}
}

View File

@ -12,6 +12,8 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Screens;
using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Overlays.Mods;
@ -314,12 +316,33 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
}
}
private ModSettingChangeTracker modSettingChangeTracker;
private ScheduledDelegate debouncedModSettingsUpdate;
private void onUserModsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
{
modSettingChangeTracker?.Dispose();
if (client.Room == null)
return;
client.ChangeUserMods(mods.NewValue);
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);
}, 500);
}
private void updateBeatmapAvailability(ValueChangedEvent<BeatmapAvailability> availability)
@ -385,14 +408,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
if (client != null)
client.LoadRequested -= onLoadRequested;
modSettingChangeTracker?.Dispose();
}
private class UserModSelectOverlay : LocalPlayerModSelectOverlay
{
public UserModSelectOverlay()
{
CustomiseButton.Alpha = 0;
}
}
}
}

View File

@ -18,7 +18,6 @@ using System.Threading;
using osu.Framework.Threading;
using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
namespace osu.Game.Screens.Select.Details
@ -83,32 +82,22 @@ namespace osu.Game.Screens.Select.Details
mods.BindValueChanged(modsChanged, true);
}
private readonly List<ISettingsItem> references = new List<ISettingsItem>();
private ModSettingChangeTracker modSettingChangeTracker;
private ScheduledDelegate debouncedStatisticsUpdate;
private void modsChanged(ValueChangedEvent<IReadOnlyList<Mod>> mods)
{
// TODO: find a more permanent solution for this if/when it is needed in other components.
// this is generating drawables for the only purpose of storing bindable references.
foreach (var r in references)
r.Dispose();
modSettingChangeTracker?.Dispose();
references.Clear();
ScheduledDelegate debounce = null;
foreach (var mod in mods.NewValue.OfType<IApplicableToDifficulty>())
modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue);
modSettingChangeTracker.SettingChanged += m =>
{
foreach (var setting in mod.CreateSettingsControls().OfType<ISettingsItem>())
{
setting.SettingChanged += () =>
{
debounce?.Cancel();
debounce = Scheduler.AddDelayed(updateStatistics, 100);
};
if (!(m is IApplicableToDifficulty))
return;
references.Add(setting);
}
}
debouncedStatisticsUpdate?.Cancel();
debouncedStatisticsUpdate = Scheduler.AddDelayed(updateStatistics, 100);
};
updateStatistics();
}
@ -173,6 +162,7 @@ namespace osu.Game.Screens.Select.Details
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
modSettingChangeTracker?.Dispose();
starDifficultyCancellationSource?.Cancel();
}