1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 09:27:29 +08:00

Added a way for mod settings to be kept when changing ruleset + test

This commit is contained in:
Terochi 2023-02-21 19:05:10 +01:00
parent ee87a29376
commit 191604340f
3 changed files with 91 additions and 5 deletions

View File

@ -21,6 +21,7 @@ using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Tests.Mods;
using osuTK;
using osuTK.Input;
@ -371,6 +372,53 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("no mod selected", () => SelectedMods.Value.Count == 0);
}
[Test]
public void TestKeepSharedSettingsFromSimilarMods()
{
const float setting_change = 1.2f;
createScreen();
changeRuleset(0);
AddStep("select difficulty adjust mod", () => SelectedMods.Value = new[] { Ruleset.Value.CreateInstance().CreateMod<ModDifficultyAdjust>()! });
changeRuleset(0);
AddAssert("ensure mod still selected", () => SelectedMods.Value.SingleOrDefault() is OsuModDifficultyAdjust);
AddStep("change mod settings", () =>
{
var osuMod = (getMod() as OsuModDifficultyAdjust)!;
osuMod.ExtendedLimits.Value = true;
osuMod.CircleSize.Value = setting_change;
osuMod.DrainRate.Value = setting_change;
osuMod.OverallDifficulty.Value = setting_change;
osuMod.ApproachRate.Value = setting_change;
});
changeRuleset(1);
AddAssert("taiko variant selected", () => SelectedMods.Value.SingleOrDefault() is TaikoModDifficultyAdjust);
AddAssert("shared settings didn't change", () =>
{
var taikoMod = getMod() as TaikoModDifficultyAdjust;
return
taikoMod?.ExtendedLimits.Value == true &&
taikoMod?.DrainRate.Value == setting_change &&
taikoMod?.OverallDifficulty.Value == setting_change;
});
AddAssert("non-shared settings at default", () =>
{
var taikoMod = getMod() as TaikoModDifficultyAdjust;
if (taikoMod == null)
return false;
return taikoMod.ScrollSpeed.Value == taikoMod.ScrollSpeed.Default;
});
ModDifficultyAdjust getMod() => (SelectedMods.Value.Single() as ModDifficultyAdjust)!;
}
[Test]
public void TestExternallySetCustomizedMod()
{

View File

@ -393,8 +393,11 @@ namespace osu.Game
Ruleset.BindValueChanged(onRulesetChanged);
Beatmap.BindValueChanged(onBeatmapChanged);
SelectedMods.BindValueChanged(change => Logger.Log($"{modSetting(change.OldValue)} => {modSetting(change.NewValue)}"));
}
private object modSetting(IReadOnlyList<Mod> mods) => mods.OfType<ModDoubleTime>().FirstOrDefault()?.GetSettingsSourceProperties().First().Item2.GetValue(mods.OfType<ModDoubleTime>().First())!;
private void addFilesWarning()
{
var realmStore = new RealmFileStore(realm, Storage);
@ -626,7 +629,8 @@ namespace osu.Game
return;
}
var previouslySelectedMods = SelectedMods.Value.ToArray();
//for some reason emptying SelectedMods resets all SettingSources Bindables to default value
var previouslySelectedMods = SelectedMods.Value.Select(mod => mod.DeepClone()).ToArray();
if (!SelectedMods.Disabled)
SelectedMods.Value = Array.Empty<Mod>();
@ -634,7 +638,16 @@ namespace osu.Game
AvailableMods.Value = dict;
if (!SelectedMods.Disabled)
SelectedMods.Value = previouslySelectedMods.Select(m => instance.CreateModFromAcronym(m.Acronym)).Where(m => m != null).ToArray();
{
SelectedMods.Value = previouslySelectedMods.Select(oldMod =>
{
Mod newMod = instance.CreateModFromAcronym(oldMod.Acronym);
newMod?.CopyFromSimilar(oldMod);
return newMod;
}).Where(m => m != null).ToArray();
}
void revertRulesetChange() => Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First();
}

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Rulesets.UI;
using osu.Game.Utils;
@ -139,6 +140,30 @@ namespace osu.Game.Rulesets.Mods
return result;
}
/// <summary>
/// Copies all shared mod setting values from <paramref name="source"/> into this instance.
/// </summary>
/// <param name="source">The mod to copy properties from.</param>
public void CopyFromSimilar(Mod source)
{
Dictionary<string, object> oldSettings = new Dictionary<string, object>();
foreach (var (_, property) in source.GetSettingsSourceProperties())
{
oldSettings.Add(property.Name.ToSnakeCase(), property.GetValue(source)!);
}
foreach (var (_, property) in this.GetSettingsSourceProperties())
{
var targetBindable = (IBindable)property.GetValue(this)!;
if (!oldSettings.TryGetValue(property.Name.ToSnakeCase(), out object? sourceSetting))
continue;
CopyAdjustedSetting(targetBindable, sourceSetting);
}
}
/// <summary>
/// Copies mod setting values from <paramref name="source"/> into this instance, overwriting all existing settings.
/// </summary>
@ -148,10 +173,10 @@ namespace osu.Game.Rulesets.Mods
if (source.GetType() != GetType())
throw new ArgumentException($"Expected mod of type {GetType()}, got {source.GetType()}.", nameof(source));
foreach (var (_, prop) in this.GetSettingsSourceProperties())
foreach (var (_, property) in this.GetSettingsSourceProperties())
{
var targetBindable = (IBindable)prop.GetValue(this)!;
var sourceBindable = (IBindable)prop.GetValue(source)!;
var targetBindable = (IBindable)property.GetValue(this)!;
var sourceBindable = (IBindable)property.GetValue(source)!;
CopyAdjustedSetting(targetBindable, sourceBindable);
}