mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 08:27:49 +08:00
Merge pull request #28445 from bdach/mania-key-count-change-force-reload
Attempt full editor reload on key count change
This commit is contained in:
commit
90481223dd
@ -0,0 +1,45 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Tests.Editor
|
||||||
|
{
|
||||||
|
public partial class TestSceneManiaEditorSaving : EditorSavingTestScene
|
||||||
|
{
|
||||||
|
protected override Ruleset CreateRuleset() => new ManiaRuleset();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestKeyCountChange()
|
||||||
|
{
|
||||||
|
LabelledSliderBar<float> keyCount = null!;
|
||||||
|
|
||||||
|
AddStep("go to setup screen", () => InputManager.Key(Key.F4));
|
||||||
|
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<LabelledSliderBar<float>>().First(), () => Is.Not.Null);
|
||||||
|
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
|
||||||
|
AddStep("change key count to 8", () =>
|
||||||
|
{
|
||||||
|
keyCount.Current.Value = 8;
|
||||||
|
});
|
||||||
|
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<ReloadEditorDialog>);
|
||||||
|
AddStep("refuse", () => InputManager.Key(Key.Number2));
|
||||||
|
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
|
||||||
|
|
||||||
|
AddStep("change key count to 8 again", () =>
|
||||||
|
{
|
||||||
|
keyCount.Current.Value = 8;
|
||||||
|
});
|
||||||
|
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().Single().CurrentDialog, Is.InstanceOf<ReloadEditorDialog>);
|
||||||
|
AddStep("acquiesce", () => InputManager.Key(Key.Number1));
|
||||||
|
AddUntilStep("beatmap became 8K", () => Game.Beatmap.Value.BeatmapInfo.Difficulty.CircleSize, () => Is.EqualTo(8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,20 +3,155 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Setup;
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Edit.Setup
|
namespace osu.Game.Rulesets.Mania.Edit.Setup
|
||||||
{
|
{
|
||||||
public partial class ManiaDifficultySection : DifficultySection
|
public partial class ManiaDifficultySection : SetupSection
|
||||||
{
|
{
|
||||||
|
public override LocalisableString Title => EditorSetupStrings.DifficultyHeader;
|
||||||
|
|
||||||
|
private LabelledSliderBar<float> keyCountSlider { get; set; } = null!;
|
||||||
|
private LabelledSliderBar<float> healthDrainSlider { get; set; } = null!;
|
||||||
|
private LabelledSliderBar<float> overallDifficultySlider { get; set; } = null!;
|
||||||
|
private LabelledSliderBar<double> baseVelocitySlider { get; set; } = null!;
|
||||||
|
private LabelledSliderBar<double> tickRateSlider { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Editor? editor { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IEditorChangeHandler? changeHandler { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
CircleSizeSlider.Label = BeatmapsetsStrings.ShowStatsCsMania;
|
Children = new Drawable[]
|
||||||
CircleSizeSlider.Description = "The number of columns in the beatmap";
|
{
|
||||||
if (CircleSizeSlider.Current is BindableNumber<float> circleSizeFloat)
|
keyCountSlider = new LabelledSliderBar<float>
|
||||||
circleSizeFloat.Precision = 1;
|
{
|
||||||
|
Label = BeatmapsetsStrings.ShowStatsCsMania,
|
||||||
|
FixedLabelWidth = LABEL_WIDTH,
|
||||||
|
Description = "The number of columns in the beatmap",
|
||||||
|
Current = new BindableFloat(Beatmap.Difficulty.CircleSize)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
healthDrainSlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = BeatmapsetsStrings.ShowStatsDrain,
|
||||||
|
FixedLabelWidth = LABEL_WIDTH,
|
||||||
|
Description = EditorSetupStrings.DrainRateDescription,
|
||||||
|
Current = new BindableFloat(Beatmap.Difficulty.DrainRate)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
overallDifficultySlider = new LabelledSliderBar<float>
|
||||||
|
{
|
||||||
|
Label = BeatmapsetsStrings.ShowStatsAccuracy,
|
||||||
|
FixedLabelWidth = LABEL_WIDTH,
|
||||||
|
Description = EditorSetupStrings.OverallDifficultyDescription,
|
||||||
|
Current = new BindableFloat(Beatmap.Difficulty.OverallDifficulty)
|
||||||
|
{
|
||||||
|
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
|
||||||
|
MinValue = 0,
|
||||||
|
MaxValue = 10,
|
||||||
|
Precision = 0.1f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
baseVelocitySlider = new LabelledSliderBar<double>
|
||||||
|
{
|
||||||
|
Label = EditorSetupStrings.BaseVelocity,
|
||||||
|
FixedLabelWidth = LABEL_WIDTH,
|
||||||
|
Description = EditorSetupStrings.BaseVelocityDescription,
|
||||||
|
Current = new BindableDouble(Beatmap.Difficulty.SliderMultiplier)
|
||||||
|
{
|
||||||
|
Default = 1.4,
|
||||||
|
MinValue = 0.4,
|
||||||
|
MaxValue = 3.6,
|
||||||
|
Precision = 0.01f,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tickRateSlider = new LabelledSliderBar<double>
|
||||||
|
{
|
||||||
|
Label = EditorSetupStrings.TickRate,
|
||||||
|
FixedLabelWidth = LABEL_WIDTH,
|
||||||
|
Description = EditorSetupStrings.TickRateDescription,
|
||||||
|
Current = new BindableDouble(Beatmap.Difficulty.SliderTickRate)
|
||||||
|
{
|
||||||
|
Default = 1,
|
||||||
|
MinValue = 1,
|
||||||
|
MaxValue = 4,
|
||||||
|
Precision = 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
keyCountSlider.Current.BindValueChanged(updateKeyCount);
|
||||||
|
healthDrainSlider.Current.BindValueChanged(_ => updateValues());
|
||||||
|
overallDifficultySlider.Current.BindValueChanged(_ => updateValues());
|
||||||
|
baseVelocitySlider.Current.BindValueChanged(_ => updateValues());
|
||||||
|
tickRateSlider.Current.BindValueChanged(_ => updateValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool updatingKeyCount;
|
||||||
|
|
||||||
|
private void updateKeyCount(ValueChangedEvent<float> keyCount)
|
||||||
|
{
|
||||||
|
if (updatingKeyCount) return;
|
||||||
|
|
||||||
|
updateValues();
|
||||||
|
|
||||||
|
if (editor == null) return;
|
||||||
|
|
||||||
|
updatingKeyCount = true;
|
||||||
|
|
||||||
|
editor.Reload().ContinueWith(t =>
|
||||||
|
{
|
||||||
|
if (!t.GetResultSafely())
|
||||||
|
{
|
||||||
|
Schedule(() =>
|
||||||
|
{
|
||||||
|
changeHandler!.RestoreState(-1);
|
||||||
|
Beatmap.Difficulty.CircleSize = keyCountSlider.Current.Value = keyCount.OldValue;
|
||||||
|
updatingKeyCount = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updatingKeyCount = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateValues()
|
||||||
|
{
|
||||||
|
// for now, update these on commit rather than making BeatmapMetadata bindables.
|
||||||
|
// after switching database engines we can reconsider if switching to bindables is a good direction.
|
||||||
|
Beatmap.Difficulty.CircleSize = keyCountSlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.SliderMultiplier = baseVelocitySlider.Current.Value;
|
||||||
|
Beatmap.Difficulty.SliderTickRate = tickRateSlider.Current.Value;
|
||||||
|
|
||||||
|
Beatmap.UpdateAllHitObjects();
|
||||||
|
Beatmap.SaveState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,7 +421,7 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
|
|
||||||
public override RulesetSetupSection CreateEditorSetupSection() => new ManiaSetupSection();
|
public override RulesetSetupSection CreateEditorSetupSection() => new ManiaSetupSection();
|
||||||
|
|
||||||
public override DifficultySection CreateEditorDifficultySection() => new ManiaDifficultySection();
|
public override SetupSection CreateEditorDifficultySection() => new ManiaDifficultySection();
|
||||||
|
|
||||||
public int GetKeyCount(IBeatmapInfo beatmapInfo, IReadOnlyList<Mod>? mods = null)
|
public int GetKeyCount(IBeatmapInfo beatmapInfo, IReadOnlyList<Mod>? mods = null)
|
||||||
=> ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo), mods);
|
=> ManiaBeatmapConverter.GetColumnCount(LegacyBeatmapConversionDifficultyInfo.FromBeatmapInfo(beatmapInfo), mods);
|
||||||
|
@ -49,6 +49,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ContinueEditing => new TranslatableString(getKey(@"continue_editing"), @"Oops, continue editing");
|
public static LocalisableString ContinueEditing => new TranslatableString(getKey(@"continue_editing"), @"Oops, continue editing");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "The editor must be reloaded to apply this change. The beatmap will be saved."
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorReloadDialogHeader => new TranslatableString(getKey(@"editor_reload_dialog_header"), @"The editor must be reloaded to apply this change. The beatmap will be saved.");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,6 +540,8 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
|
|
||||||
protected void Redo() => changeHandler?.RestoreState(1);
|
protected void Redo() => changeHandler?.RestoreState(1);
|
||||||
|
|
||||||
|
void IEditorChangeHandler.RestoreState(int direction) => changeHandler?.RestoreState(direction);
|
||||||
|
|
||||||
public void Save(bool userTriggered = true) => save(currentSkin.Value, userTriggered);
|
public void Save(bool userTriggered = true) => save(currentSkin.Value, userTriggered);
|
||||||
|
|
||||||
private void save(Skin skin, bool userTriggered = true)
|
private void save(Skin skin, bool userTriggered = true)
|
||||||
|
@ -401,6 +401,6 @@ namespace osu.Game.Rulesets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Can be overridden to alter the difficulty section to the editor beatmap setup screen.
|
/// Can be overridden to alter the difficulty section to the editor beatmap setup screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual DifficultySection? CreateEditorDifficultySection() => null;
|
public virtual SetupSection? CreateEditorDifficultySection() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1231,6 +1231,27 @@ namespace osu.Game.Screens.Edit
|
|||||||
loader?.CancelPendingDifficultySwitch();
|
loader?.CancelPendingDifficultySwitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<bool> Reload()
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
dialogOverlay.Push(new ReloadEditorDialog(
|
||||||
|
reload: () =>
|
||||||
|
{
|
||||||
|
bool reloadedSuccessfully = attemptMutationOperation(() =>
|
||||||
|
{
|
||||||
|
if (!Save())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SwitchToDifficulty(editorBeatmap.BeatmapInfo);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
tcs.SetResult(reloadedSuccessfully);
|
||||||
|
},
|
||||||
|
cancel: () => tcs.SetResult(false)));
|
||||||
|
return tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
public void HandleTimestamp(string timestamp)
|
public void HandleTimestamp(string timestamp)
|
||||||
{
|
{
|
||||||
if (!EditorTimestampParser.TryParse(timestamp, out var timeSpan, out string selection))
|
if (!EditorTimestampParser.TryParse(timestamp, out var timeSpan, out string selection))
|
||||||
|
@ -83,10 +83,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Restores an older or newer state.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="direction">The direction to restore in. If less than 0, an older state will be used. If greater than 0, a newer state will be used.</param>
|
|
||||||
public void RestoreState(int direction)
|
public void RestoreState(int direction)
|
||||||
{
|
{
|
||||||
if (TransactionActive)
|
if (TransactionActive)
|
||||||
|
@ -43,5 +43,11 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// Note that this will be a no-op if there is a change in progress via <see cref="BeginChange"/>.
|
/// Note that this will be a no-op if there is a change in progress via <see cref="BeginChange"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void SaveState();
|
void SaveState();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restores an older or newer state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="direction">The direction to restore in. If less than 0, an older state will be used. If greater than 0, a newer state will be used.</param>
|
||||||
|
void RestoreState(int direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
osu.Game/Screens/Edit/ReloadEditorDialog.cs
Normal file
34
osu.Game/Screens/Edit/ReloadEditorDialog.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Edit
|
||||||
|
{
|
||||||
|
public partial class ReloadEditorDialog : PopupDialog
|
||||||
|
{
|
||||||
|
public ReloadEditorDialog(Action reload, Action cancel)
|
||||||
|
{
|
||||||
|
HeaderText = EditorDialogsStrings.EditorReloadDialogHeader;
|
||||||
|
|
||||||
|
Icon = FontAwesome.Solid.Sync;
|
||||||
|
|
||||||
|
Buttons = new PopupDialogButton[]
|
||||||
|
{
|
||||||
|
new PopupDialogOkButton
|
||||||
|
{
|
||||||
|
Text = DialogStrings.Confirm,
|
||||||
|
Action = reload
|
||||||
|
},
|
||||||
|
new PopupDialogCancelButton
|
||||||
|
{
|
||||||
|
Text = DialogStrings.Cancel,
|
||||||
|
Action = cancel
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user