Expose available mod state outwardly as a bindable

This commit is contained in:
Bartłomiej Dach
2022-05-25 22:20:10 +02:00
parent f0303d76e8
commit 071e158a29

View File

@ -34,6 +34,15 @@ namespace osu.Game.Overlays.Mods
[Cached] [Cached]
public Bindable<IReadOnlyList<Mod>> SelectedMods { get; private set; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>()); public Bindable<IReadOnlyList<Mod>> SelectedMods { get; private set; } = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
/// <summary>
/// Contains a dictionary with the current <see cref="ModState"/> of all mods applicable for the current ruleset.
/// </summary>
/// <remarks>
/// Contrary to <see cref="OsuGameBase.AvailableMods"/> and <see cref="globalAvailableMods"/>, the <see cref="Mod"/> instances
/// inside the <see cref="ModState"/> objects are owned solely by this <see cref="ModSelectOverlay"/> instance.
/// </remarks>
public Bindable<Dictionary<ModType, IReadOnlyList<ModState>>> AvailableMods { get; } = new Bindable<Dictionary<ModType, IReadOnlyList<ModState>>>(new Dictionary<ModType, IReadOnlyList<ModState>>());
private Func<Mod, bool> isValidMod = m => true; private Func<Mod, bool> isValidMod = m => true;
/// <summary> /// <summary>
@ -79,9 +88,9 @@ namespace osu.Game.Overlays.Mods
yield return new DeselectAllModsButton(this); yield return new DeselectAllModsButton(this);
} }
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> availableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>(); private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> globalAvailableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
private readonly Dictionary<ModType, IReadOnlyList<ModState>> localAvailableMods = new Dictionary<ModType, IReadOnlyList<ModState>>();
private IEnumerable<ModState> allLocalAvailableMods => localAvailableMods.SelectMany(pair => pair.Value); private IEnumerable<ModState> allAvailableMods => AvailableMods.Value.SelectMany(pair => pair.Value);
private readonly BindableBool customisationVisible = new BindableBool(); private readonly BindableBool customisationVisible = new BindableBool();
@ -204,13 +213,13 @@ namespace osu.Game.Overlays.Mods
}) })
}; };
availableMods.BindTo(game.AvailableMods); globalAvailableMods.BindTo(game.AvailableMods);
} }
protected override void LoadComplete() protected override void LoadComplete()
{ {
// this is called before base call so that the mod state is populated early, and the transition in `PopIn()` can play out properly. // this is called before base call so that the mod state is populated early, and the transition in `PopIn()` can play out properly.
availableMods.BindValueChanged(_ => createLocalMods(), true); globalAvailableMods.BindValueChanged(_ => createLocalMods(), true);
base.LoadComplete(); base.LoadComplete();
@ -275,9 +284,9 @@ namespace osu.Game.Overlays.Mods
private void createLocalMods() private void createLocalMods()
{ {
localAvailableMods.Clear(); var newLocalAvailableMods = new Dictionary<ModType, IReadOnlyList<ModState>>();
foreach (var (modType, mods) in availableMods.Value) foreach (var (modType, mods) in globalAvailableMods.Value)
{ {
var modStates = mods.SelectMany(ModUtils.FlattenMod) var modStates = mods.SelectMany(ModUtils.FlattenMod)
.Select(mod => new ModState(mod.DeepClone())) .Select(mod => new ModState(mod.DeepClone()))
@ -286,18 +295,19 @@ namespace osu.Game.Overlays.Mods
foreach (var modState in modStates) foreach (var modState in modStates)
modState.Active.BindValueChanged(_ => updateFromInternalSelection()); modState.Active.BindValueChanged(_ => updateFromInternalSelection());
localAvailableMods[modType] = modStates; newLocalAvailableMods[modType] = modStates;
} }
AvailableMods.Value = newLocalAvailableMods;
filterMods(); filterMods();
foreach (var column in columnFlow.Columns) foreach (var column in columnFlow.Columns)
column.AvailableMods = localAvailableMods.GetValueOrDefault(column.ModType, Array.Empty<ModState>()); column.AvailableMods = AvailableMods.Value.GetValueOrDefault(column.ModType, Array.Empty<ModState>());
} }
private void filterMods() private void filterMods()
{ {
foreach (var modState in allLocalAvailableMods) foreach (var modState in allAvailableMods)
modState.Filtered.Value = !modState.Mod.HasImplementation || !IsValidMod.Invoke(modState.Mod); modState.Filtered.Value = !modState.Mod.HasImplementation || !IsValidMod.Invoke(modState.Mod);
} }
@ -378,7 +388,7 @@ namespace osu.Game.Overlays.Mods
var newSelection = new List<Mod>(); var newSelection = new List<Mod>();
foreach (var modState in allLocalAvailableMods) foreach (var modState in allAvailableMods)
{ {
var matchingSelectedMod = SelectedMods.Value.SingleOrDefault(selected => selected.GetType() == modState.Mod.GetType()); var matchingSelectedMod = SelectedMods.Value.SingleOrDefault(selected => selected.GetType() == modState.Mod.GetType());
@ -405,9 +415,9 @@ namespace osu.Game.Overlays.Mods
if (externalSelectionUpdateInProgress) if (externalSelectionUpdateInProgress)
return; return;
var candidateSelection = allLocalAvailableMods.Where(modState => modState.Active.Value) var candidateSelection = allAvailableMods.Where(modState => modState.Active.Value)
.Select(modState => modState.Mod) .Select(modState => modState.Mod)
.ToArray(); .ToArray();
SelectedMods.Value = ComputeNewModsFromSelection(SelectedMods.Value, candidateSelection); SelectedMods.Value = ComputeNewModsFromSelection(SelectedMods.Value, candidateSelection);
} }