1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 12:57:36 +08:00

Merge pull request #25265 from bdach/skin-editor-freeze

Fix skin editor freezing game if opened during active gameplay
This commit is contained in:
Dean Herbert 2023-10-28 02:28:54 +09:00 committed by GitHub
commit e6445343b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 5 deletions

View File

@ -5,6 +5,7 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
@ -18,6 +19,7 @@ using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Edit.Components;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD.HitErrorMeters; using osu.Game.Screens.Play.HUD.HitErrorMeters;
using osu.Game.Skinning;
using osu.Game.Tests.Beatmaps.IO; using osu.Game.Tests.Beatmaps.IO;
using osuTK; using osuTK;
using osuTK.Input; using osuTK.Input;
@ -31,7 +33,7 @@ namespace osu.Game.Tests.Visual.Navigation
private SkinEditor skinEditor => Game.ChildrenOfType<SkinEditor>().FirstOrDefault(); private SkinEditor skinEditor => Game.ChildrenOfType<SkinEditor>().FirstOrDefault();
[Test] [Test]
public void TestEditComponentDuringGameplay() public void TestEditComponentFromGameplayScene()
{ {
advanceToSongSelect(); advanceToSongSelect();
openSkinEditor(); openSkinEditor();
@ -69,6 +71,28 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default); AddAssert("value is less than default", () => hitErrorMeter.JudgementLineThickness.Value < hitErrorMeter.JudgementLineThickness.Default);
} }
[Test]
public void TestMutateProtectedSkinDuringGameplay()
{
advanceToSongSelect();
AddStep("set default skin", () => Game.Dependencies.Get<SkinManager>().CurrentSkinInfo.SetDefault());
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
AddStep("enable NF", () => Game.SelectedMods.Value = new[] { new OsuModNoFail() });
AddStep("enter gameplay", () => InputManager.Key(Key.Enter));
AddUntilStep("wait for player", () =>
{
DismissAnyNotifications();
return Game.ScreenStack.CurrentScreen is Player;
});
openSkinEditor();
AddUntilStep("current skin is mutable", () => !Game.Dependencies.Get<SkinManager>().CurrentSkin.Value.SkinInfo.Value.Protected);
}
[Test] [Test]
public void TestComponentsDeselectedOnSkinEditorHide() public void TestComponentsDeselectedOnSkinEditorHide()
{ {

View File

@ -21,5 +21,11 @@ namespace osu.Game.Database
/// Whether this import should use hard links rather than file copy operations if available. /// Whether this import should use hard links rather than file copy operations if available.
/// </summary> /// </summary>
public bool PreferHardLinks { get; set; } public bool PreferHardLinks { get; set; }
/// <summary>
/// If set to <see langword="true"/>, this import will not respect <see cref="RealmArchiveModelImporter{TModel}.PauseImports"/>.
/// This is useful for cases where an import <em>must</em> complete even if gameplay is in progress.
/// </summary>
public bool ImportImmediately { get; set; }
} }
} }

View File

@ -261,7 +261,7 @@ namespace osu.Game.Database
/// <param name="cancellationToken">An optional cancellation token.</param> /// <param name="cancellationToken">An optional cancellation token.</param>
public virtual Live<TModel>? ImportModel(TModel item, ArchiveReader? archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) => Realm.Run(realm => public virtual Live<TModel>? ImportModel(TModel item, ArchiveReader? archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) => Realm.Run(realm =>
{ {
pauseIfNecessary(cancellationToken); pauseIfNecessary(parameters, cancellationToken);
TModel? existing; TModel? existing;
@ -560,9 +560,9 @@ namespace osu.Game.Database
/// <returns>Whether to perform deletion.</returns> /// <returns>Whether to perform deletion.</returns>
protected virtual bool ShouldDeleteArchive(string path) => false; protected virtual bool ShouldDeleteArchive(string path) => false;
private void pauseIfNecessary(CancellationToken cancellationToken) private void pauseIfNecessary(ImportParameters importParameters, CancellationToken cancellationToken)
{ {
if (!PauseImports) if (!PauseImports || importParameters.ImportImmediately)
return; return;
Logger.Log($@"{GetType().Name} is being paused."); Logger.Log($@"{GetType().Name} is being paused.");

View File

@ -182,7 +182,10 @@ namespace osu.Game.Skinning
Name = NamingUtils.GetNextBestName(existingSkinNames, $@"{s.Name} (modified)") Name = NamingUtils.GetNextBestName(existingSkinNames, $@"{s.Name} (modified)")
}; };
var result = skinImporter.ImportModel(skinInfo); var result = skinImporter.ImportModel(skinInfo, parameters: new ImportParameters
{
ImportImmediately = true // to avoid possible deadlocks when editing skin during gameplay.
});
if (result != null) if (result != null)
{ {