mirror of
https://github.com/osukey/osukey.git
synced 2025-08-07 16:43:52 +09:00
Merge pull request #8260 from smoogipoo/add-workingbeatmap-timeout
Add beatmap loading timeout to prevent runaway loading scenarios
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
@ -60,8 +61,9 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ruleset">The <see cref="RulesetInfo"/> to create a playable <see cref="IBeatmap"/> for.</param>
|
/// <param name="ruleset">The <see cref="RulesetInfo"/> to create a playable <see cref="IBeatmap"/> for.</param>
|
||||||
/// <param name="mods">The <see cref="Mod"/>s to apply to the <see cref="IBeatmap"/>.</param>
|
/// <param name="mods">The <see cref="Mod"/>s to apply to the <see cref="IBeatmap"/>.</param>
|
||||||
|
/// <param name="timeout">The maximum length in milliseconds to wait for load to complete. Defaults to 10,000ms.</param>
|
||||||
/// <returns>The converted <see cref="IBeatmap"/>.</returns>
|
/// <returns>The converted <see cref="IBeatmap"/>.</returns>
|
||||||
/// <exception cref="BeatmapInvalidForRulesetException">If <see cref="Beatmap"/> could not be converted to <paramref name="ruleset"/>.</exception>
|
/// <exception cref="BeatmapInvalidForRulesetException">If <see cref="Beatmap"/> could not be converted to <paramref name="ruleset"/>.</exception>
|
||||||
IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods = null);
|
IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods = null, TimeSpan? timeout = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,9 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <returns>The applicable <see cref="IBeatmapConverter"/>.</returns>
|
/// <returns>The applicable <see cref="IBeatmapConverter"/>.</returns>
|
||||||
protected virtual IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => ruleset.CreateBeatmapConverter(beatmap);
|
protected virtual IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap, Ruleset ruleset) => ruleset.CreateBeatmapConverter(beatmap);
|
||||||
|
|
||||||
public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods = null)
|
public IBeatmap GetPlayableBeatmap(RulesetInfo ruleset, IReadOnlyList<Mod> mods = null, TimeSpan? timeout = null)
|
||||||
|
{
|
||||||
|
using (var cancellationSource = new CancellationTokenSource(timeout ?? TimeSpan.FromSeconds(10)))
|
||||||
{
|
{
|
||||||
mods ??= Array.Empty<Mod>();
|
mods ??= Array.Empty<Mod>();
|
||||||
|
|
||||||
@ -97,7 +99,12 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
// Apply conversion mods
|
// Apply conversion mods
|
||||||
foreach (var mod in mods.OfType<IApplicableToBeatmapConverter>())
|
foreach (var mod in mods.OfType<IApplicableToBeatmapConverter>())
|
||||||
|
{
|
||||||
|
if (cancellationSource.IsCancellationRequested)
|
||||||
|
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||||
|
|
||||||
mod.ApplyToBeatmapConverter(converter);
|
mod.ApplyToBeatmapConverter(converter);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert
|
// Convert
|
||||||
IBeatmap converted = converter.Convert();
|
IBeatmap converted = converter.Convert();
|
||||||
@ -109,8 +116,13 @@ namespace osu.Game.Beatmaps
|
|||||||
converted.BeatmapInfo.BaseDifficulty = converted.BeatmapInfo.BaseDifficulty.Clone();
|
converted.BeatmapInfo.BaseDifficulty = converted.BeatmapInfo.BaseDifficulty.Clone();
|
||||||
|
|
||||||
foreach (var mod in mods.OfType<IApplicableToDifficulty>())
|
foreach (var mod in mods.OfType<IApplicableToDifficulty>())
|
||||||
|
{
|
||||||
|
if (cancellationSource.IsCancellationRequested)
|
||||||
|
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||||
|
|
||||||
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
|
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted);
|
IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted);
|
||||||
|
|
||||||
@ -118,21 +130,35 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
|
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
|
||||||
foreach (var obj in converted.HitObjects)
|
foreach (var obj in converted.HitObjects)
|
||||||
|
{
|
||||||
|
if (cancellationSource.IsCancellationRequested)
|
||||||
|
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||||
|
|
||||||
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
|
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var mod in mods.OfType<IApplicableToHitObject>())
|
foreach (var mod in mods.OfType<IApplicableToHitObject>())
|
||||||
{
|
{
|
||||||
foreach (var obj in converted.HitObjects)
|
foreach (var obj in converted.HitObjects)
|
||||||
|
{
|
||||||
|
if (cancellationSource.IsCancellationRequested)
|
||||||
|
throw new BeatmapLoadTimeoutException(BeatmapInfo);
|
||||||
|
|
||||||
mod.ApplyToHitObject(obj);
|
mod.ApplyToHitObject(obj);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
processor?.PostProcess();
|
processor?.PostProcess();
|
||||||
|
|
||||||
foreach (var mod in mods.OfType<IApplicableToBeatmap>())
|
foreach (var mod in mods.OfType<IApplicableToBeatmap>())
|
||||||
|
{
|
||||||
|
cancellationSource.Token.ThrowIfCancellationRequested();
|
||||||
mod.ApplyToBeatmap(converted);
|
mod.ApplyToBeatmap(converted);
|
||||||
|
}
|
||||||
|
|
||||||
return converted;
|
return converted;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CancellationTokenSource loadCancellation = new CancellationTokenSource();
|
private CancellationTokenSource loadCancellation = new CancellationTokenSource();
|
||||||
|
|
||||||
@ -297,5 +323,13 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
private void recreate() => lazy = new Lazy<T>(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication);
|
private void recreate() => lazy = new Lazy<T>(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BeatmapLoadTimeoutException : TimeoutException
|
||||||
|
{
|
||||||
|
public BeatmapLoadTimeoutException(BeatmapInfo beatmapInfo)
|
||||||
|
: base($"Timed out while loading beatmap ({beatmapInfo}).")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ using osuTK.Input;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
@ -86,7 +87,18 @@ namespace osu.Game.Screens.Edit
|
|||||||
// todo: remove caching of this and consume via editorBeatmap?
|
// todo: remove caching of this and consume via editorBeatmap?
|
||||||
dependencies.Cache(beatDivisor);
|
dependencies.Cache(beatDivisor);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, "Could not load beatmap successfully!");
|
||||||
|
// couldn't load, hard abort!
|
||||||
|
this.Exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap));
|
AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap));
|
||||||
|
|
||||||
dependencies.CacheAs(editorBeatmap);
|
dependencies.CacheAs(editorBeatmap);
|
||||||
|
@ -23,6 +23,7 @@ using osu.Framework.Graphics.Cursor;
|
|||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
@ -311,6 +312,8 @@ namespace osu.Game.Screens.Select
|
|||||||
Content = getBPMRange(b),
|
Content = getBPMRange(b),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
IBeatmap playableBeatmap;
|
IBeatmap playableBeatmap;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -326,6 +329,11 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s)));
|
labels.AddRange(playableBeatmap.GetStatistics().Select(s => new InfoLabel(s)));
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error(e, "Could not load beatmap successfully!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return labels.ToArray();
|
return labels.ToArray();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user