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:
parent
e86444c4bf
commit
05a21fbbe0
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user