mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 15:17:27 +08:00
Merge pull request #28420 from bdach/mutually-exclusive-save-related-actions
Disallow running save-related operations concurrently
This commit is contained in:
commit
cd3b455341
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -22,6 +23,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
public TestGameplayButton TestGameplayButton { get; private set; }
|
public TestGameplayButton TestGameplayButton { get; private set; }
|
||||||
|
|
||||||
|
private IBindable<bool> saveInProgress;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider, Editor editor)
|
private void load(OverlayColourProvider colourProvider, Editor editor)
|
||||||
{
|
{
|
||||||
@ -74,6 +77,15 @@ namespace osu.Game.Screens.Edit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
saveInProgress = editor.MutationTracker.InProgress.GetBoundCopy();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
saveInProgress.BindValueChanged(_ => TestGameplayButton.Enabled.Value = !saveInProgress.Value, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -35,6 +36,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Overlays.OSD;
|
using osu.Game.Overlays.OSD;
|
||||||
@ -49,6 +51,7 @@ using osu.Game.Screens.Edit.GameplayTest;
|
|||||||
using osu.Game.Screens.Edit.Setup;
|
using osu.Game.Screens.Edit.Setup;
|
||||||
using osu.Game.Screens.Edit.Timing;
|
using osu.Game.Screens.Edit.Timing;
|
||||||
using osu.Game.Screens.Edit.Verify;
|
using osu.Game.Screens.Edit.Verify;
|
||||||
|
using osu.Game.Screens.OnlinePlay;
|
||||||
using osu.Game.Screens.Play;
|
using osu.Game.Screens.Play;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -142,6 +145,13 @@ namespace osu.Game.Screens.Edit
|
|||||||
private readonly Bindable<bool> samplePlaybackDisabled = new Bindable<bool>();
|
private readonly Bindable<bool> samplePlaybackDisabled = new Bindable<bool>();
|
||||||
|
|
||||||
private bool canSave;
|
private bool canSave;
|
||||||
|
private readonly List<MenuItem> saveRelatedMenuItems = new List<MenuItem>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tracks ongoing mutually-exclusive operations related to changing the beatmap
|
||||||
|
/// (e.g. save, export).
|
||||||
|
/// </summary>
|
||||||
|
public OngoingOperationTracker MutationTracker { get; } = new OngoingOperationTracker();
|
||||||
|
|
||||||
protected bool ExitConfirmed { get; private set; }
|
protected bool ExitConfirmed { get; private set; }
|
||||||
|
|
||||||
@ -328,7 +338,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
new MenuItem(CommonStrings.MenuBarFile)
|
new MenuItem(CommonStrings.MenuBarFile)
|
||||||
{
|
{
|
||||||
Items = createFileMenuItems()
|
Items = createFileMenuItems().ToList()
|
||||||
},
|
},
|
||||||
new MenuItem(CommonStrings.MenuBarEdit)
|
new MenuItem(CommonStrings.MenuBarEdit)
|
||||||
{
|
{
|
||||||
@ -382,6 +392,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
bottomBar = new BottomBar(),
|
bottomBar = new BottomBar(),
|
||||||
|
MutationTracker,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
|
changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);
|
||||||
@ -402,6 +413,12 @@ namespace osu.Game.Screens.Edit
|
|||||||
Mode.BindValueChanged(onModeChanged, true);
|
Mode.BindValueChanged(onModeChanged, true);
|
||||||
|
|
||||||
musicController.TrackChanged += onTrackChanged;
|
musicController.TrackChanged += onTrackChanged;
|
||||||
|
|
||||||
|
MutationTracker.InProgress.BindValueChanged(_ =>
|
||||||
|
{
|
||||||
|
foreach (var item in saveRelatedMenuItems)
|
||||||
|
item.Action.Disabled = MutationTracker.InProgress.Value;
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
@ -440,12 +457,13 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
if (HasUnsavedChanges)
|
if (HasUnsavedChanges)
|
||||||
{
|
{
|
||||||
dialogOverlay.Push(new SaveRequiredPopupDialog("The beatmap will be saved in order to test it.", () =>
|
dialogOverlay.Push(new SaveRequiredPopupDialog("The beatmap will be saved in order to test it.", () => attemptMutationOperation(() =>
|
||||||
{
|
{
|
||||||
if (!Save()) return;
|
if (!Save()) return false;
|
||||||
|
|
||||||
pushEditorPlayer();
|
pushEditorPlayer();
|
||||||
}));
|
return true;
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -455,6 +473,26 @@ namespace osu.Game.Screens.Edit
|
|||||||
void pushEditorPlayer() => this.Push(new EditorPlayerLoader(this));
|
void pushEditorPlayer() => this.Push(new EditorPlayerLoader(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool attemptMutationOperation(Func<bool> mutationOperation)
|
||||||
|
{
|
||||||
|
if (MutationTracker.InProgress.Value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
using (MutationTracker.BeginOperation())
|
||||||
|
return mutationOperation.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool attemptAsyncMutationOperation(Func<Task> mutationTask)
|
||||||
|
{
|
||||||
|
if (MutationTracker.InProgress.Value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var operation = MutationTracker.BeginOperation();
|
||||||
|
var task = mutationTask.Invoke();
|
||||||
|
task.FireAndForget(operation.Dispose, _ => operation.Dispose());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the currently edited beatmap.
|
/// Saves the currently edited beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -520,8 +558,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
if (e.Repeat)
|
if (e.Repeat)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Save();
|
return attemptMutationOperation(Save);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -787,7 +824,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private void confirmExitWithSave()
|
private void confirmExitWithSave()
|
||||||
{
|
{
|
||||||
if (!Save()) return;
|
if (!attemptMutationOperation(Save))
|
||||||
|
return;
|
||||||
|
|
||||||
ExitConfirmed = true;
|
ExitConfirmed = true;
|
||||||
this.Exit();
|
this.Exit();
|
||||||
@ -1020,25 +1058,35 @@ namespace osu.Game.Screens.Edit
|
|||||||
lastSavedHash = changeHandler?.CurrentStateHash;
|
lastSavedHash = changeHandler?.CurrentStateHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MenuItem> createFileMenuItems() => new List<MenuItem>
|
private IEnumerable<MenuItem> createFileMenuItems()
|
||||||
{
|
{
|
||||||
createDifficultyCreationMenu(),
|
yield return createDifficultyCreationMenu();
|
||||||
createDifficultySwitchMenu(),
|
yield return createDifficultySwitchMenu();
|
||||||
new OsuMenuItemSpacer(),
|
yield return new OsuMenuItemSpacer();
|
||||||
new EditorMenuItem(EditorStrings.DeleteDifficulty, MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } },
|
yield return new EditorMenuItem(EditorStrings.DeleteDifficulty, MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } };
|
||||||
new OsuMenuItemSpacer(),
|
yield return new OsuMenuItemSpacer();
|
||||||
new EditorMenuItem(WebCommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()),
|
|
||||||
createExportMenu(),
|
var save = new EditorMenuItem(WebCommonStrings.ButtonsSave, MenuItemType.Standard, () => attemptMutationOperation(Save));
|
||||||
new OsuMenuItemSpacer(),
|
saveRelatedMenuItems.Add(save);
|
||||||
new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, this.Exit)
|
yield return save;
|
||||||
};
|
|
||||||
|
if (RuntimeInfo.IsDesktop)
|
||||||
|
{
|
||||||
|
var export = createExportMenu();
|
||||||
|
saveRelatedMenuItems.AddRange(export.Items);
|
||||||
|
yield return export;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new OsuMenuItemSpacer();
|
||||||
|
yield return new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, this.Exit);
|
||||||
|
}
|
||||||
|
|
||||||
private EditorMenuItem createExportMenu()
|
private EditorMenuItem createExportMenu()
|
||||||
{
|
{
|
||||||
var exportItems = new List<MenuItem>
|
var exportItems = new List<MenuItem>
|
||||||
{
|
{
|
||||||
new EditorMenuItem(EditorStrings.ExportForEditing, MenuItemType.Standard, () => exportBeatmap(false)) { Action = { Disabled = !RuntimeInfo.IsDesktop } },
|
new EditorMenuItem(EditorStrings.ExportForEditing, MenuItemType.Standard, () => exportBeatmap(false)),
|
||||||
new EditorMenuItem(EditorStrings.ExportForCompatibility, MenuItemType.Standard, () => exportBeatmap(true)) { Action = { Disabled = !RuntimeInfo.IsDesktop } },
|
new EditorMenuItem(EditorStrings.ExportForCompatibility, MenuItemType.Standard, () => exportBeatmap(true)),
|
||||||
};
|
};
|
||||||
|
|
||||||
return new EditorMenuItem(CommonStrings.Export) { Items = exportItems };
|
return new EditorMenuItem(CommonStrings.Export) { Items = exportItems };
|
||||||
@ -1048,24 +1096,25 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
if (HasUnsavedChanges)
|
if (HasUnsavedChanges)
|
||||||
{
|
{
|
||||||
dialogOverlay.Push(new SaveRequiredPopupDialog("The beatmap will be saved in order to export it.", () =>
|
dialogOverlay.Push(new SaveRequiredPopupDialog("The beatmap will be saved in order to export it.", () => attemptAsyncMutationOperation(() =>
|
||||||
{
|
{
|
||||||
if (!Save()) return;
|
if (!Save())
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
runExport();
|
return runExport();
|
||||||
}));
|
})));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
runExport();
|
attemptAsyncMutationOperation(runExport);
|
||||||
}
|
}
|
||||||
|
|
||||||
void runExport()
|
Task runExport()
|
||||||
{
|
{
|
||||||
if (legacy)
|
if (legacy)
|
||||||
beatmapManager.ExportLegacy(Beatmap.Value.BeatmapSetInfo);
|
return beatmapManager.ExportLegacy(Beatmap.Value.BeatmapSetInfo);
|
||||||
else
|
else
|
||||||
beatmapManager.Export(Beatmap.Value.BeatmapSetInfo);
|
return beatmapManager.Export(Beatmap.Value.BeatmapSetInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,6 +1165,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
foreach (var ruleset in rulesets.AvailableRulesets)
|
foreach (var ruleset in rulesets.AvailableRulesets)
|
||||||
rulesetItems.Add(new EditorMenuItem(ruleset.Name, MenuItemType.Standard, () => CreateNewDifficulty(ruleset)));
|
rulesetItems.Add(new EditorMenuItem(ruleset.Name, MenuItemType.Standard, () => CreateNewDifficulty(ruleset)));
|
||||||
|
|
||||||
|
saveRelatedMenuItems.AddRange(rulesetItems);
|
||||||
|
|
||||||
return new EditorMenuItem(EditorStrings.CreateNewDifficulty) { Items = rulesetItems };
|
return new EditorMenuItem(EditorStrings.CreateNewDifficulty) { Items = rulesetItems };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,10 +1176,14 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
dialogOverlay.Push(new SaveRequiredPopupDialog("This beatmap will be saved in order to create another difficulty.", () =>
|
dialogOverlay.Push(new SaveRequiredPopupDialog("This beatmap will be saved in order to create another difficulty.", () =>
|
||||||
{
|
{
|
||||||
if (!Save())
|
attemptMutationOperation(() =>
|
||||||
return;
|
{
|
||||||
|
if (!Save())
|
||||||
|
return false;
|
||||||
|
|
||||||
CreateNewDifficulty(rulesetInfo);
|
CreateNewDifficulty(rulesetInfo);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user