Deselect old incompatible mods if any on user mod select screen

This commit is contained in:
Bartłomiej Dach 2022-04-20 23:34:43 +02:00
parent 32722adba9
commit b7c11cdb8e
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
2 changed files with 36 additions and 12 deletions

View File

@ -168,7 +168,7 @@ protected override void LoadComplete()
foreach (var column in columnFlow)
{
column.SelectedMods.BindValueChanged(_ => updateBindableFromSelection());
column.SelectedMods.BindValueChanged(updateBindableFromSelection);
}
customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true);
@ -237,33 +237,36 @@ private void updateCustomisationVisualState()
TopLevelContent.MoveToY(-modAreaHeight, transition_duration, Easing.InOutCubic);
}
private bool selectionBindableSyncInProgress;
private void updateSelectionFromBindable()
{
if (selectionBindableSyncInProgress)
return;
selectionBindableSyncInProgress = true;
// note that selectionBindableSyncInProgress is purposefully not checked here.
// this is because in the case of mod selection in solo gameplay, a user selection of a mod can actually lead to deselection of other incompatible mods.
// to synchronise state correctly, updateBindableFromSelection() computes the final mods (including incompatibility rules) and updates SelectedMods,
// and this method then runs unconditionally again to make sure the new visual selection accurately reflects the final set of selected mods.
// selectionBindableSyncInProgress ensures that mutual infinite recursion does not happen after that unconditional call.
foreach (var column in columnFlow)
column.SelectedMods.Value = SelectedMods.Value.Where(mod => mod.Type == column.ModType).ToArray();
selectionBindableSyncInProgress = false;
}
private void updateBindableFromSelection()
private bool selectionBindableSyncInProgress;
private void updateBindableFromSelection(ValueChangedEvent<IReadOnlyList<Mod>> modSelectionChange)
{
if (selectionBindableSyncInProgress)
return;
selectionBindableSyncInProgress = true;
SelectedMods.Value = columnFlow.SelectMany(column => column.SelectedMods.Value).ToArray();
SelectedMods.Value = ComputeNewModsFromSelection(
modSelectionChange.NewValue.Except(modSelectionChange.OldValue),
modSelectionChange.OldValue.Except(modSelectionChange.NewValue));
selectionBindableSyncInProgress = false;
}
protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IEnumerable<Mod> addedMods, IEnumerable<Mod> removedMods)
=> columnFlow.SelectMany(column => column.SelectedMods.Value).ToArray();
protected override void PopIn()
{
const double fade_in_duration = 400;

View File

@ -1,8 +1,11 @@
// 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 JetBrains.Annotations;
using osu.Game.Rulesets.Mods;
using osu.Game.Utils;
using osuTK.Input;
namespace osu.Game.Overlays.Mods
@ -11,6 +14,24 @@ public class UserModSelectScreen : ModSelectScreen
{
protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys);
protected override IReadOnlyList<Mod> ComputeNewModsFromSelection(IEnumerable<Mod> addedMods, IEnumerable<Mod> removedMods)
{
IEnumerable<Mod> modsAfterRemoval = SelectedMods.Value.Except(removedMods).ToList();
// the preference is that all new mods should override potential incompatible old mods.
// in general that's a bit difficult to compute if more than one mod is added at a time,
// so be conservative and just remove all mods that aren't compatible with any one added mod.
foreach (var addedMod in addedMods)
{
if (!ModUtils.CheckCompatibleSet(modsAfterRemoval.Append(addedMod), out var invalidMods))
modsAfterRemoval = modsAfterRemoval.Except(invalidMods);
modsAfterRemoval = modsAfterRemoval.Append(addedMod).ToList();
}
return modsAfterRemoval.ToList();
}
private class UserModColumn : ModColumn
{
public UserModColumn(ModType modType, bool allowBulkSelection, [CanBeNull] Key[] toggleKeys = null)