1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 18:42:56 +08:00

Hoist ModState to overlay level

This commit is contained in:
Bartłomiej Dach 2022-05-11 19:02:45 +02:00
parent e86444c4bf
commit 05a21fbbe0
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
2 changed files with 58 additions and 58 deletions

View File

@ -20,13 +20,11 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Lists;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation;
using osu.Game.Rulesets.Mods;
using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
@ -39,6 +37,23 @@ namespace osu.Game.Overlays.Mods
public readonly ModType ModType;
private IReadOnlyList<ModState> availableMods = Array.Empty<ModState>();
/// <summary>
/// Sets the list of mods to show in this column.
/// </summary>
public IReadOnlyList<ModState> AvailableMods
{
get => availableMods;
set
{
Debug.Assert(value.All(mod => mod.Mod.Type == ModType));
availableMods = value;
asyncLoadPanels();
}
}
private Func<Mod, bool>? filter;
/// <summary>
@ -88,17 +103,6 @@ namespace osu.Game.Overlays.Mods
private readonly Key[]? toggleKeys;
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
/// <summary>
/// Contains information about state of all mods that are available for the current ruleset in this particular column.
/// </summary>
/// <remarks>
/// Note that the mod instances in this list are owned solely by this column
/// (as in, they are locally-managed clones, to ensure proper isolation from any other external instances).
/// </remarks>
private IReadOnlyList<ModState> localAvailableMods = Array.Empty<ModState>();
private readonly TextFlowContainer headerText;
private readonly Box headerBackground;
private readonly Container contentContainer;
@ -258,12 +262,8 @@ namespace osu.Game.Overlays.Mods
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game, OverlayColourProvider colourProvider, OsuColour colours)
private void load(OverlayColourProvider colourProvider, OsuColour colours)
{
availableMods.BindTo(game.AvailableMods);
updateLocalAvailableMods(asyncLoadContent: false);
availableMods.BindValueChanged(_ => updateLocalAvailableMods(asyncLoadContent: true));
headerBackground.Colour = accentColour = colours.ForModType(ModType);
if (toggleAllCheckbox != null)
@ -289,30 +289,13 @@ namespace osu.Game.Overlays.Mods
toggleAllCheckbox.LabelText = toggleAllCheckbox.Current.Value ? CommonStrings.DeselectAll : CommonStrings.SelectAll;
}
private void updateLocalAvailableMods(bool asyncLoadContent)
{
var newMods = ModUtils.FlattenMods(availableMods.Value.GetValueOrDefault(ModType) ?? Array.Empty<Mod>())
.Select(m => new ModState(m.DeepClone()))
.ToList();
if (newMods.SequenceEqual(localAvailableMods, new FuncEqualityComparer<ModState>((x, y) => ReferenceEquals(x.Mod, y.Mod))))
return;
localAvailableMods = newMods;
if (asyncLoadContent)
asyncLoadPanels();
else
onPanelsLoaded(createPanels());
}
private CancellationTokenSource? cancellationTokenSource;
private void asyncLoadPanels()
{
cancellationTokenSource?.Cancel();
var panels = createPanels();
var panels = availableMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0)));
Task? loadTask;
@ -324,12 +307,6 @@ namespace osu.Game.Overlays.Mods
});
}
private IEnumerable<ModPanel> createPanels()
{
var panels = localAvailableMods.Select(mod => CreateModPanel(mod).With(panel => panel.Shear = new Vector2(-ShearedOverlayContainer.SHEAR, 0)));
return panels;
}
private void onPanelsLoaded(IEnumerable<ModPanel> loaded)
{
panelFlow.ChildrenEnumerable = loaded;
@ -394,7 +371,7 @@ namespace osu.Game.Overlays.Mods
var newSelection = new List<Mod>();
foreach (var modState in localAvailableMods)
foreach (var modState in this.availableMods)
{
var matchingSelectedMod = mods.SingleOrDefault(selected => selected.GetType() == modState.GetType());
@ -554,10 +531,10 @@ namespace osu.Game.Overlays.Mods
int index = Array.IndexOf(toggleKeys, e.Key);
if (index < 0) return false;
var panel = panelFlow.ElementAtOrDefault(index);
if (panel == null || panel.Filtered.Value) return false;
var modState = availableMods.ElementAtOrDefault(index);
if (modState == null || modState.Filtered.Value) return false;
panel.Active.Toggle();
modState.Active.Toggle();
return true;
}

View File

@ -22,6 +22,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Input.Bindings;
using osu.Game.Localisation;
using osu.Game.Rulesets.Mods;
using osu.Game.Utils;
using osuTK;
using osuTK.Input;
@ -47,9 +48,7 @@ namespace osu.Game.Overlays.Mods
set
{
isValidMod = value ?? throw new ArgumentNullException(nameof(value));
if (IsLoaded)
updateAvailableMods();
filterMods();
}
}
@ -64,6 +63,9 @@ namespace osu.Game.Overlays.Mods
protected virtual IEnumerable<ShearedButton> CreateFooterButtons() => createDefaultFooterButtons();
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
private readonly Dictionary<ModType, IReadOnlyList<ModState>> localAvailableMods = new Dictionary<ModType, IReadOnlyList<ModState>>();
private readonly BindableBool customisationVisible = new BindableBool();
private ModSettingsArea modSettingsArea = null!;
@ -82,7 +84,7 @@ namespace osu.Game.Overlays.Mods
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OsuGameBase game, OsuColour colours)
{
Header.Title = ModSelectOverlayStrings.ModSelectTitle;
Header.Description = ModSelectOverlayStrings.ModSelectDescription;
@ -184,12 +186,16 @@ namespace osu.Game.Overlays.Mods
LighterColour = colours.Pink1
})
};
availableMods.BindTo(game.AvailableMods);
}
protected override void LoadComplete()
{
base.LoadComplete();
availableMods.BindValueChanged(_ => createLocalMods(), true);
State.BindValueChanged(_ => samplePlaybackDisabled.Value = State.Value == Visibility.Hidden, true);
// This is an optimisation to prevent refreshing the available settings controls when it can be
@ -211,8 +217,6 @@ namespace osu.Game.Overlays.Mods
customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true);
updateAvailableMods();
// Start scrolled slightly to the right to give the user a sense that
// there is more horizontal content available.
ScheduleAfterChildren(() =>
@ -272,6 +276,31 @@ namespace osu.Game.Overlays.Mods
}
};
private void createLocalMods()
{
localAvailableMods.Clear();
foreach (var (modType, mods) in availableMods.Value)
{
var modStates = mods.SelectMany(ModUtils.FlattenMod)
.Select(mod => new ModState(mod.DeepClone()))
.ToArray();
localAvailableMods[modType] = modStates;
}
filterMods();
foreach (var column in columnFlow.Columns)
column.AvailableMods = localAvailableMods.GetValueOrDefault(column.ModType, Array.Empty<ModState>());
}
private void filterMods()
{
foreach (var modState in localAvailableMods.Values.SelectMany(m => m))
modState.Filtered.Value = !modState.Mod.HasImplementation || !IsValidMod.Invoke(modState.Mod);
}
private void updateMultiplier()
{
if (multiplierDisplay == null)
@ -285,12 +314,6 @@ namespace osu.Game.Overlays.Mods
multiplierDisplay.Current.Value = multiplier;
}
private void updateAvailableMods()
{
foreach (var column in columnFlow.Columns)
column.Filter = m => m.HasImplementation && isValidMod.Invoke(m);
}
private void updateCustomisation(ValueChangedEvent<IReadOnlyList<Mod>> valueChangedEvent)
{
if (customisationButton == null)