mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 00:23:59 +09:00
Merge pull request #4320 from peppy/fix-disabled-set-crash
Ensure beatmap is not disabled before continuing with present
This commit is contained in:
@ -101,7 +101,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
int fireCount = 0;
|
int fireCount = 0;
|
||||||
|
|
||||||
// ReSharper disable once AccessToModifiedClosure
|
// ReSharper disable once AccessToModifiedClosure
|
||||||
manager.ItemAdded += (_, __, ___) => fireCount++;
|
manager.ItemAdded += (_, __) => fireCount++;
|
||||||
manager.ItemRemoved += _ => fireCount++;
|
manager.ItemRemoved += _ => fireCount++;
|
||||||
|
|
||||||
var imported = LoadOszIntoOsu(osu);
|
var imported = LoadOszIntoOsu(osu);
|
||||||
|
@ -11,7 +11,6 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
@ -50,11 +49,6 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadFailed;
|
public event Action<DownloadBeatmapSetRequest> BeatmapDownloadFailed;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fired when a beatmap load is requested (into the interactive game UI).
|
|
||||||
/// </summary>
|
|
||||||
public Action<BeatmapSetInfo> PresentBeatmap;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -151,8 +145,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
var downloadNotification = new DownloadNotification
|
var downloadNotification = new DownloadNotification
|
||||||
{
|
{
|
||||||
CompletionText = $"Imported {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}!",
|
Text = $"Downloading {beatmapSetInfo}",
|
||||||
Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var request = new DownloadBeatmapSetRequest(beatmapSetInfo, noVideo);
|
var request = new DownloadBeatmapSetRequest(beatmapSetInfo, noVideo);
|
||||||
@ -165,20 +158,10 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
request.Success += filename =>
|
request.Success += filename =>
|
||||||
{
|
{
|
||||||
downloadNotification.Text = $"Importing {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}";
|
|
||||||
|
|
||||||
Task.Factory.StartNew(() =>
|
Task.Factory.StartNew(() =>
|
||||||
{
|
{
|
||||||
// This gets scheduled back to the update thread, but we want the import to run in the background.
|
// This gets scheduled back to the update thread, but we want the import to run in the background.
|
||||||
var importedBeatmap = Import(filename);
|
Import(downloadNotification, filename);
|
||||||
|
|
||||||
downloadNotification.CompletionClickAction = () =>
|
|
||||||
{
|
|
||||||
PresentCompletedImport(importedBeatmap.Yield());
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
downloadNotification.State = ProgressNotificationState.Completed;
|
|
||||||
|
|
||||||
currentDownloads.Remove(request);
|
currentDownloads.Remove(request);
|
||||||
}, TaskCreationOptions.LongRunning);
|
}, TaskCreationOptions.LongRunning);
|
||||||
};
|
};
|
||||||
@ -221,12 +204,6 @@ namespace osu.Game.Beatmaps
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PresentCompletedImport(IEnumerable<BeatmapSetInfo> imported)
|
|
||||||
{
|
|
||||||
base.PresentCompletedImport(imported);
|
|
||||||
PresentBeatmap?.Invoke(imported.LastOrDefault());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get an existing download request if it exists.
|
/// Get an existing download request if it exists.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Database
|
|||||||
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
|
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
|
||||||
where TFileModel : INamedFileInfo, new()
|
where TFileModel : INamedFileInfo, new()
|
||||||
{
|
{
|
||||||
public delegate void ItemAddedDelegate(TModel model, bool existing, bool silent);
|
public delegate void ItemAddedDelegate(TModel model, bool existing);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set an endpoint for notifications to be posted to.
|
/// Set an endpoint for notifications to be posted to.
|
||||||
@ -113,7 +113,7 @@ namespace osu.Game.Database
|
|||||||
ContextFactory = contextFactory;
|
ContextFactory = contextFactory;
|
||||||
|
|
||||||
ModelStore = modelStore;
|
ModelStore = modelStore;
|
||||||
ModelStore.ItemAdded += (item, silent) => handleEvent(() => ItemAdded?.Invoke(item, false, silent));
|
ModelStore.ItemAdded += item => handleEvent(() => ItemAdded?.Invoke(item, false));
|
||||||
ModelStore.ItemRemoved += s => handleEvent(() => ItemRemoved?.Invoke(s));
|
ModelStore.ItemRemoved += s => handleEvent(() => ItemRemoved?.Invoke(s));
|
||||||
|
|
||||||
Files = new FileStore(contextFactory, storage);
|
Files = new FileStore(contextFactory, storage);
|
||||||
@ -131,14 +131,18 @@ namespace osu.Game.Database
|
|||||||
/// <param name="paths">One or more archive locations on disk.</param>
|
/// <param name="paths">One or more archive locations on disk.</param>
|
||||||
public void Import(params string[] paths)
|
public void Import(params string[] paths)
|
||||||
{
|
{
|
||||||
var notification = new ProgressNotification
|
var notification = new ProgressNotification { State = ProgressNotificationState.Active };
|
||||||
{
|
|
||||||
Text = "Import is initialising...",
|
|
||||||
Progress = 0,
|
|
||||||
State = ProgressNotificationState.Active,
|
|
||||||
};
|
|
||||||
|
|
||||||
PostNotification?.Invoke(notification);
|
PostNotification?.Invoke(notification);
|
||||||
|
Import(notification, paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Import(ProgressNotification notification, params string[] paths)
|
||||||
|
{
|
||||||
|
notification.Progress = 0;
|
||||||
|
notification.Text = "Import is initialising...";
|
||||||
|
|
||||||
|
var term = $"{typeof(TModel).Name.Replace("Info", "").ToLower()}";
|
||||||
|
|
||||||
List<TModel> imported = new List<TModel>();
|
List<TModel> imported = new List<TModel>();
|
||||||
|
|
||||||
@ -151,7 +155,18 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
notification.Text = $"Importing ({++current} of {paths.Length})\n{Path.GetFileName(path)}";
|
var text = "Importing ";
|
||||||
|
|
||||||
|
if (path.Length > 1)
|
||||||
|
text += $"{++current} of {paths.Length} {term}s..";
|
||||||
|
else
|
||||||
|
text += $"{term}..";
|
||||||
|
|
||||||
|
// only show the filename if it isn't a temporary one (as those look ugly).
|
||||||
|
if (!path.Contains(Path.GetTempPath()))
|
||||||
|
text += $"\n{Path.GetFileName(path)}";
|
||||||
|
|
||||||
|
notification.Text = text;
|
||||||
|
|
||||||
imported.Add(Import(path));
|
imported.Add(Import(path));
|
||||||
|
|
||||||
@ -171,13 +186,20 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
notification.CompletionText = $"Imported {current} {typeof(TModel).Name.Replace("Info", "").ToLower()}s!";
|
notification.CompletionText = imported.Count == 1
|
||||||
notification.CompletionClickAction += () =>
|
? $"Imported {imported.First()}!"
|
||||||
|
: $"Imported {current} {term}s!";
|
||||||
|
|
||||||
|
if (imported.Count > 0 && PresentImport != null)
|
||||||
{
|
{
|
||||||
if (imported.Count > 0)
|
notification.CompletionText += " Click to view.";
|
||||||
PresentCompletedImport(imported);
|
notification.CompletionClickAction = () =>
|
||||||
return true;
|
{
|
||||||
};
|
PresentImport?.Invoke(imported);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
notification.State = ProgressNotificationState.Completed;
|
notification.State = ProgressNotificationState.Completed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,9 +232,10 @@ namespace osu.Game.Database
|
|||||||
return import;
|
return import;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void PresentCompletedImport(IEnumerable<TModel> imported)
|
/// <summary>
|
||||||
{
|
/// Fired when the user requests to view the resulting import.
|
||||||
}
|
/// </summary>
|
||||||
|
public Action<IEnumerable<TModel>> PresentImport;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Import an item from an <see cref="ArchiveReader"/>.
|
/// Import an item from an <see cref="ArchiveReader"/>.
|
||||||
@ -228,7 +251,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
model.Hash = computeHash(archive);
|
model.Hash = computeHash(archive);
|
||||||
|
|
||||||
return Import(model, false, archive);
|
return Import(model, archive);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -262,9 +285,8 @@ namespace osu.Game.Database
|
|||||||
/// Import an item from a <see cref="TModel"/>.
|
/// Import an item from a <see cref="TModel"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The model to be imported.</param>
|
/// <param name="item">The model to be imported.</param>
|
||||||
/// <param name="silent">Whether the user should be notified fo the import.</param>
|
|
||||||
/// <param name="archive">An optional archive to use for model population.</param>
|
/// <param name="archive">An optional archive to use for model population.</param>
|
||||||
public TModel Import(TModel item, bool silent = false, ArchiveReader archive = null)
|
public TModel Import(TModel item, ArchiveReader archive = null)
|
||||||
{
|
{
|
||||||
delayEvents();
|
delayEvents();
|
||||||
|
|
||||||
@ -284,7 +306,7 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
Undelete(existing);
|
Undelete(existing);
|
||||||
Logger.Log($"Found existing {typeof(TModel)} for {item} (ID {existing.ID}). Skipping import.", LoggingTarget.Database);
|
Logger.Log($"Found existing {typeof(TModel)} for {item} (ID {existing.ID}). Skipping import.", LoggingTarget.Database);
|
||||||
handleEvent(() => ItemAdded?.Invoke(existing, true, silent));
|
handleEvent(() => ItemAdded?.Invoke(existing, true));
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +316,7 @@ namespace osu.Game.Database
|
|||||||
Populate(item, archive);
|
Populate(item, archive);
|
||||||
|
|
||||||
// import to store
|
// import to store
|
||||||
ModelStore.Add(item, silent);
|
ModelStore.Add(item);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -16,9 +16,7 @@ namespace osu.Game.Database
|
|||||||
public abstract class MutableDatabaseBackedStore<T> : DatabaseBackedStore
|
public abstract class MutableDatabaseBackedStore<T> : DatabaseBackedStore
|
||||||
where T : class, IHasPrimaryKey, ISoftDelete
|
where T : class, IHasPrimaryKey, ISoftDelete
|
||||||
{
|
{
|
||||||
public delegate void ItemAddedDelegate(T model, bool silent);
|
public event Action<T> ItemAdded;
|
||||||
|
|
||||||
public event ItemAddedDelegate ItemAdded;
|
|
||||||
public event Action<T> ItemRemoved;
|
public event Action<T> ItemRemoved;
|
||||||
|
|
||||||
protected MutableDatabaseBackedStore(IDatabaseContextFactory contextFactory, Storage storage = null)
|
protected MutableDatabaseBackedStore(IDatabaseContextFactory contextFactory, Storage storage = null)
|
||||||
@ -35,8 +33,7 @@ namespace osu.Game.Database
|
|||||||
/// Add a <see cref="T"/> to the database.
|
/// Add a <see cref="T"/> to the database.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">The item to add.</param>
|
/// <param name="item">The item to add.</param>
|
||||||
/// <param name="silent">Whether the user should be notified of the addition.</param>
|
public void Add(T item)
|
||||||
public void Add(T item, bool silent)
|
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
{
|
{
|
||||||
@ -44,7 +41,7 @@ namespace osu.Game.Database
|
|||||||
context.Attach(item);
|
context.Attach(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemAdded?.Invoke(item, silent);
|
ItemAdded?.Invoke(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -57,7 +54,7 @@ namespace osu.Game.Database
|
|||||||
usage.Context.Update(item);
|
usage.Context.Update(item);
|
||||||
|
|
||||||
ItemRemoved?.Invoke(item);
|
ItemRemoved?.Invoke(item);
|
||||||
ItemAdded?.Invoke(item, true);
|
ItemAdded?.Invoke(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -94,7 +91,7 @@ namespace osu.Game.Database
|
|||||||
item.DeletePending = false;
|
item.DeletePending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemAdded?.Invoke(item, true);
|
ItemAdded?.Invoke(item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,8 +167,6 @@ namespace osu.Game
|
|||||||
{
|
{
|
||||||
this.frameworkConfig = frameworkConfig;
|
this.frameworkConfig = frameworkConfig;
|
||||||
|
|
||||||
ScoreManager.ItemAdded += (score, _, silent) => Schedule(() => LoadScore(score, silent));
|
|
||||||
|
|
||||||
if (!Host.IsPrimaryInstance)
|
if (!Host.IsPrimaryInstance)
|
||||||
{
|
{
|
||||||
Logger.Log(@"osu! does not support multiple running instances.", LoggingTarget.Runtime, LogLevel.Error);
|
Logger.Log(@"osu! does not support multiple running instances.", LoggingTarget.Runtime, LogLevel.Error);
|
||||||
@ -217,63 +215,12 @@ namespace osu.Game
|
|||||||
externalLinkOpener.OpenUrlExternally(url);
|
externalLinkOpener.OpenUrlExternally(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledDelegate scoreLoad;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show a beatmap set as an overlay.
|
/// Show a beatmap set as an overlay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="setId">The set to display.</param>
|
/// <param name="setId">The set to display.</param>
|
||||||
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.FetchAndShowBeatmapSet(setId);
|
public void ShowBeatmapSet(int setId) => beatmapSetOverlay.FetchAndShowBeatmapSet(setId);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Present a beatmap at song select.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="beatmap">The beatmap to select.</param>
|
|
||||||
public void PresentBeatmap(BeatmapSetInfo beatmap)
|
|
||||||
{
|
|
||||||
if (menuScreen == null)
|
|
||||||
{
|
|
||||||
Schedule(() => PresentBeatmap(beatmap));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseAllOverlays(false);
|
|
||||||
|
|
||||||
void setBeatmap()
|
|
||||||
{
|
|
||||||
if (Beatmap.Disabled)
|
|
||||||
{
|
|
||||||
Schedule(setBeatmap);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var databasedSet = beatmap.OnlineBeatmapSetID != null ? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID) : BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash);
|
|
||||||
|
|
||||||
if (databasedSet != null)
|
|
||||||
{
|
|
||||||
// Use first beatmap available for current ruleset, else switch ruleset.
|
|
||||||
var first = databasedSet.Beatmaps.Find(b => b.Ruleset == ruleset.Value) ?? databasedSet.Beatmaps.First();
|
|
||||||
|
|
||||||
ruleset.Value = first.Ruleset;
|
|
||||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (screenStack.CurrentScreen)
|
|
||||||
{
|
|
||||||
case SongSelect _:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// navigate to song select if we are not already there.
|
|
||||||
|
|
||||||
menuScreen.MakeCurrent();
|
|
||||||
menuScreen.LoadToSolo();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
setBeatmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Show a user's profile as an overlay.
|
/// Show a user's profile as an overlay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -286,19 +233,44 @@ namespace osu.Game
|
|||||||
/// <param name="beatmapId">The beatmap to show.</param>
|
/// <param name="beatmapId">The beatmap to show.</param>
|
||||||
public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
|
public void ShowBeatmap(int beatmapId) => beatmapSetOverlay.FetchAndShowBeatmap(beatmapId);
|
||||||
|
|
||||||
protected void LoadScore(ScoreInfo score, bool silent)
|
/// <summary>
|
||||||
|
/// Present a beatmap at song select immediately.
|
||||||
|
/// The user should have already requested this interactively.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to select.</param>
|
||||||
|
public void PresentBeatmap(BeatmapSetInfo beatmap)
|
||||||
{
|
{
|
||||||
if (silent)
|
var databasedSet = beatmap.OnlineBeatmapSetID != null
|
||||||
return;
|
? BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID)
|
||||||
|
: BeatmapManager.QueryBeatmapSet(s => s.Hash == beatmap.Hash);
|
||||||
|
|
||||||
scoreLoad?.Cancel();
|
if (databasedSet == null)
|
||||||
|
|
||||||
if (menuScreen == null)
|
|
||||||
{
|
{
|
||||||
scoreLoad = Schedule(() => LoadScore(score, false));
|
Logger.Log("The requested beatmap could not be loaded.", LoggingTarget.Information);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
performFromMainMenu(() =>
|
||||||
|
{
|
||||||
|
// we might already be at song select, so a check is required before performing the load to solo.
|
||||||
|
if (menuScreen.IsCurrentScreen())
|
||||||
|
menuScreen.LoadToSolo();
|
||||||
|
|
||||||
|
// Use first beatmap available for current ruleset, else switch ruleset.
|
||||||
|
var first = databasedSet.Beatmaps.Find(b => b.Ruleset == ruleset.Value) ?? databasedSet.Beatmaps.First();
|
||||||
|
|
||||||
|
ruleset.Value = first.Ruleset;
|
||||||
|
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
|
||||||
|
}, $"load {beatmap}", bypassScreenAllowChecks: true, targetScreen: typeof(PlaySongSelect));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Present a score's replay immediately.
|
||||||
|
/// The user should have already requested this interactively.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="beatmap">The beatmap to select.</param>
|
||||||
|
public void PresentScore(ScoreInfo score)
|
||||||
|
{
|
||||||
var databasedScore = ScoreManager.GetScore(score);
|
var databasedScore = ScoreManager.GetScore(score);
|
||||||
var databasedScoreInfo = databasedScore.ScoreInfo;
|
var databasedScoreInfo = databasedScore.ScoreInfo;
|
||||||
if (databasedScore.Replay == null)
|
if (databasedScore.Replay == null)
|
||||||
@ -314,14 +286,40 @@ namespace osu.Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((screenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange == false)
|
performFromMainMenu(() =>
|
||||||
|
{
|
||||||
|
ruleset.Value = databasedScoreInfo.Ruleset;
|
||||||
|
|
||||||
|
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
|
||||||
|
Beatmap.Value.Mods.Value = databasedScoreInfo.Mods;
|
||||||
|
|
||||||
|
menuScreen.Push(new PlayerLoader(() => new ReplayPlayer(databasedScore)));
|
||||||
|
}, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ScheduledDelegate performFromMainMenuTask;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Perform an action only after returning to the main menu.
|
||||||
|
/// Eagerly tries to exit the current screen until it succeeds.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The action to perform once we are in the correct state.</param>
|
||||||
|
/// <param name="taskName">The task name to display in a notification (if we can't immediately reach the main menu state).</param>
|
||||||
|
/// <param name="targetScreen">An optional target screen type. If this screen is already current we can immediately perform the action without returning to the menu.</param>
|
||||||
|
/// <param name="bypassScreenAllowChecks">Whether checking <see cref="IOsuScreen.AllowExternalScreenChange"/> should be bypassed.</param>
|
||||||
|
private void performFromMainMenu(Action action, string taskName, Type targetScreen = null, bool bypassScreenAllowChecks = false)
|
||||||
|
{
|
||||||
|
performFromMainMenuTask?.Cancel();
|
||||||
|
|
||||||
|
// if the current screen does not allow screen changing, give the user an option to try again later.
|
||||||
|
if (!bypassScreenAllowChecks && (screenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange == false)
|
||||||
{
|
{
|
||||||
notifications.Post(new SimpleNotification
|
notifications.Post(new SimpleNotification
|
||||||
{
|
{
|
||||||
Text = $"Click here to watch {databasedScoreInfo.User.Username} on {databasedScoreInfo.Beatmap}",
|
Text = $"Click here to {taskName}",
|
||||||
Activated = () =>
|
Activated = () =>
|
||||||
{
|
{
|
||||||
loadScore();
|
performFromMainMenu(action, taskName, targetScreen, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -329,24 +327,26 @@ namespace osu.Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadScore();
|
CloseAllOverlays(false);
|
||||||
|
|
||||||
void loadScore()
|
// we may already be at the target screen type.
|
||||||
|
if (targetScreen != null && screenStack.CurrentScreen?.GetType() == targetScreen)
|
||||||
{
|
{
|
||||||
if (!menuScreen.IsCurrentScreen() || Beatmap.Disabled)
|
action();
|
||||||
{
|
return;
|
||||||
menuScreen.MakeCurrent();
|
|
||||||
this.Delay(500).Schedule(loadScore, out scoreLoad);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ruleset.Value = databasedScoreInfo.Ruleset;
|
|
||||||
|
|
||||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
|
|
||||||
Beatmap.Value.Mods.Value = databasedScoreInfo.Mods;
|
|
||||||
|
|
||||||
menuScreen.Push(new PlayerLoader(() => new ReplayPlayer(databasedScore)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all conditions have been met to continue with the action.
|
||||||
|
if (menuScreen?.IsCurrentScreen() == true && !Beatmap.Disabled)
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// menuScreen may not be initialised yet (null check required).
|
||||||
|
menuScreen?.MakeCurrent();
|
||||||
|
|
||||||
|
performFromMainMenuTask = Schedule(() => performFromMainMenu(action, taskName));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
@ -370,8 +370,10 @@ namespace osu.Game
|
|||||||
|
|
||||||
BeatmapManager.PostNotification = n => notifications?.Post(n);
|
BeatmapManager.PostNotification = n => notifications?.Post(n);
|
||||||
BeatmapManager.GetStableStorage = GetStorageForStableInstall;
|
BeatmapManager.GetStableStorage = GetStorageForStableInstall;
|
||||||
|
BeatmapManager.PresentImport = items => PresentBeatmap(items.First());
|
||||||
|
|
||||||
BeatmapManager.PresentBeatmap = PresentBeatmap;
|
ScoreManager.PostNotification = n => notifications?.Post(n);
|
||||||
|
ScoreManager.PresentImport = items => PresentScore(items.First());
|
||||||
|
|
||||||
Container logoContainer;
|
Container logoContainer;
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ namespace osu.Game.Overlays.Direct
|
|||||||
|
|
||||||
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
private void onRequestFailure(Exception e) => Schedule(() => attachDownload(null));
|
||||||
|
|
||||||
private void setAdded(BeatmapSetInfo s, bool existing, bool silent) => setDownloadStateFromManager(s, DownloadState.LocallyAvailable);
|
private void setAdded(BeatmapSetInfo s, bool existing) => setDownloadStateFromManager(s, DownloadState.LocallyAvailable);
|
||||||
|
|
||||||
private void setRemoved(BeatmapSetInfo s) => setDownloadStateFromManager(s, DownloadState.NotDownloaded);
|
private void setRemoved(BeatmapSetInfo s) => setDownloadStateFromManager(s, DownloadState.NotDownloaded);
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(BeatmapManager beatmaps, IBindable<WorkingBeatmap> beatmap)
|
private void load(BeatmapManager beatmaps, IBindable<WorkingBeatmap> beatmap)
|
||||||
{
|
{
|
||||||
beatmaps.GetAllUsableBeatmapSets().ForEach(b => addBeatmapSet(b, false, false));
|
beatmaps.GetAllUsableBeatmapSets().ForEach(b => addBeatmapSet(b, false));
|
||||||
beatmaps.ItemAdded += addBeatmapSet;
|
beatmaps.ItemAdded += addBeatmapSet;
|
||||||
beatmaps.ItemRemoved += removeBeatmapSet;
|
beatmaps.ItemRemoved += removeBeatmapSet;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ namespace osu.Game.Overlays.Music
|
|||||||
beatmapBacking.ValueChanged += _ => updateSelectedSet();
|
beatmapBacking.ValueChanged += _ => updateSelectedSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addBeatmapSet(BeatmapSetInfo obj, bool existing, bool silent) => Schedule(() =>
|
private void addBeatmapSet(BeatmapSetInfo obj, bool existing) => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (existing)
|
if (existing)
|
||||||
return;
|
return;
|
||||||
|
@ -212,7 +212,7 @@ namespace osu.Game.Overlays
|
|||||||
beatmapSets.Insert(index, beatmapSetInfo);
|
beatmapSets.Insert(index, beatmapSetInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBeatmapAdded(BeatmapSetInfo obj, bool existing, bool silent)
|
private void handleBeatmapAdded(BeatmapSetInfo obj, bool existing)
|
||||||
{
|
{
|
||||||
if (existing)
|
if (existing)
|
||||||
return;
|
return;
|
||||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
|
|
||||||
private void itemRemoved(SkinInfo s) => Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != s.ID).ToArray());
|
private void itemRemoved(SkinInfo s) => Schedule(() => skinDropdown.Items = skinDropdown.Items.Where(i => i.ID != s.ID).ToArray());
|
||||||
|
|
||||||
private void itemAdded(SkinInfo s, bool existing, bool silent)
|
private void itemAdded(SkinInfo s, bool existing)
|
||||||
{
|
{
|
||||||
if (existing)
|
if (existing)
|
||||||
return;
|
return;
|
||||||
|
@ -178,5 +178,7 @@ namespace osu.Game.Scoring
|
|||||||
{
|
{
|
||||||
public string Acronym { get; set; }
|
public string Acronym { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"{User} playing {Beatmap}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Screens
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether a top-level component should be allowed to exit the current screen to, for example,
|
/// Whether a top-level component should be allowed to exit the current screen to, for example,
|
||||||
/// complete an import.
|
/// complete an import. Note that this can be overridden by a user if they specifically request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool AllowExternalScreenChange { get; }
|
bool AllowExternalScreenChange { get; }
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Screens.Multi.Match.Components
|
|||||||
hasBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID) != null;
|
hasBeatmap = beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmap.OnlineBeatmapID) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void beatmapAdded(BeatmapSetInfo model, bool existing, bool silent)
|
private void beatmapAdded(BeatmapSetInfo model, bool existing)
|
||||||
{
|
{
|
||||||
if (Beatmap.Value == null)
|
if (Beatmap.Value == null)
|
||||||
return;
|
return;
|
||||||
|
@ -202,7 +202,7 @@ namespace osu.Game.Screens.Multi.Match
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle the case where a beatmap is imported (and can be used by this match).
|
/// Handle the case where a beatmap is imported (and can be used by this match).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void beatmapAdded(BeatmapSetInfo model, bool existing, bool silent) => Schedule(() =>
|
private void beatmapAdded(BeatmapSetInfo model, bool existing) => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (Beatmap.Value != beatmapManager.DefaultBeatmap)
|
if (Beatmap.Value != beatmapManager.DefaultBeatmap)
|
||||||
return;
|
return;
|
||||||
|
@ -298,7 +298,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
var score = CreateScore();
|
var score = CreateScore();
|
||||||
if (RulesetContainer.ReplayScore == null)
|
if (RulesetContainer.ReplayScore == null)
|
||||||
scoreManager.Import(score, true);
|
scoreManager.Import(score);
|
||||||
|
|
||||||
this.Push(CreateResults(score));
|
this.Push(CreateResults(score));
|
||||||
|
|
||||||
|
@ -582,7 +582,7 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onBeatmapSetAdded(BeatmapSetInfo s, bool existing, bool silent) => Carousel.UpdateBeatmapSet(s);
|
private void onBeatmapSetAdded(BeatmapSetInfo s, bool existing) => Carousel.UpdateBeatmapSet(s);
|
||||||
private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s);
|
private void onBeatmapSetRemoved(BeatmapSetInfo s) => Carousel.RemoveBeatmapSet(s);
|
||||||
private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
|
private void onBeatmapRestored(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
|
||||||
private void onBeatmapHidden(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
|
private void onBeatmapHidden(BeatmapInfo b) => Carousel.UpdateBeatmapSet(beatmaps.QueryBeatmapSet(s => s.ID == b.BeatmapSetInfoID));
|
||||||
|
Reference in New Issue
Block a user