Merge branch 'master' into fix-mirror-note-conversion

This commit is contained in:
Dean Herbert
2018-08-17 14:47:16 +09:00
committed by GitHub
12 changed files with 136 additions and 19 deletions

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework; using osu.Framework;
using osu.Framework.Development;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.IPC; using osu.Game.IPC;
@ -51,7 +52,7 @@ namespace osu.Desktop
} }
} }
private static int allowableExceptions = 1; private static int allowableExceptions = DebugUtils.IsDebugBuild ? 0 : 1;
/// <summary> /// <summary>
/// Allow a maximum of one unhandled exception, per second of execution. /// Allow a maximum of one unhandled exception, per second of execution.
@ -62,9 +63,11 @@ namespace osu.Desktop
{ {
bool continueExecution = Interlocked.Decrement(ref allowableExceptions) >= 0; bool continueExecution = Interlocked.Decrement(ref allowableExceptions) >= 0;
Logger.Log($"Unhandled exception has been {(continueExecution ? "allowed" : "denied")} with {allowableExceptions} more allowable exceptions."); Logger.Log($"Unhandled exception has been {(continueExecution ? "allowed with {allowableExceptions} more allowable exceptions" : "denied")} .");
// restore the stock of allowable exceptions after a short delay.
Task.Delay(1000).ContinueWith(_ => Interlocked.Increment(ref allowableExceptions)); Task.Delay(1000).ContinueWith(_ => Interlocked.Increment(ref allowableExceptions));
return continueExecution; return continueExecution;
} }
} }

View File

@ -18,8 +18,10 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
/// <summary> /// <summary>
/// An arbitrary maximum amount of iterations to perform in <see cref="RunWhile"/>. /// An arbitrary maximum amount of iterations to perform in <see cref="RunWhile"/>.
/// The specific value is not super important - enough such that no false-positives occur. /// The specific value is not super important - enough such that no false-positives occur.
///
/// /b/933228 requires at least 23 iterations.
/// </summary> /// </summary>
private const int max_rng_iterations = 20; private const int max_rng_iterations = 30;
/// <summary> /// <summary>
/// The last pattern. /// The last pattern.

View File

@ -12,7 +12,7 @@ using osu.Game.Rulesets.Osu.UI;
namespace osu.Game.Rulesets.Osu.Beatmaps namespace osu.Game.Rulesets.Osu.Beatmaps
{ {
internal class OsuBeatmapConverter : BeatmapConverter<OsuHitObject> public class OsuBeatmapConverter : BeatmapConverter<OsuHitObject>
{ {
public OsuBeatmapConverter(IBeatmap beatmap) public OsuBeatmapConverter(IBeatmap beatmap)
: base(beatmap) : base(beatmap)

View File

@ -8,7 +8,7 @@ using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Beatmaps namespace osu.Game.Rulesets.Osu.Beatmaps
{ {
internal class OsuBeatmapProcessor : BeatmapProcessor public class OsuBeatmapProcessor : BeatmapProcessor
{ {
public OsuBeatmapProcessor(IBeatmap beatmap) public OsuBeatmapProcessor(IBeatmap beatmap)
: base(beatmap) : base(beatmap)

View File

@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.Objects
/// </summary> /// </summary>
public int SpinsRequired { get; protected set; } = 1; public int SpinsRequired { get; protected set; } = 1;
public override bool NewCombo => true;
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty) protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
{ {
base.ApplyDefaultsToSelf(controlPointInfo, difficulty); base.ApplyDefaultsToSelf(controlPointInfo, difficulty);

View File

@ -11,7 +11,9 @@ using osu.Game.Audio;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Catch.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Tests.Beatmaps.Formats namespace osu.Game.Tests.Beatmaps.Formats
@ -187,14 +189,46 @@ namespace osu.Game.Tests.Beatmaps.Formats
} }
[Test] [Test]
public void TestDecodeBeatmapComboOffsets() public void TestDecodeBeatmapComboOffsetsOsu()
{ {
var decoder = new LegacyBeatmapDecoder(); var decoder = new LegacyBeatmapDecoder();
using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu")) using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu"))
using (var stream = new StreamReader(resStream)) using (var stream = new StreamReader(resStream))
{ {
var beatmap = decoder.Decode(stream); var beatmap = decoder.Decode(stream);
Assert.AreEqual(3, ((IHasCombo)beatmap.HitObjects[0]).ComboOffset);
var converted = new OsuBeatmapConverter(beatmap).Convert();
new OsuBeatmapProcessor(converted).PreProcess();
new OsuBeatmapProcessor(converted).PostProcess();
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndex);
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndex);
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndex);
Assert.AreEqual(6, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndex);
Assert.AreEqual(11, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndex);
Assert.AreEqual(14, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndex);
}
}
[Test]
public void TestDecodeBeatmapComboOffsetsCatch()
{
var decoder = new LegacyBeatmapDecoder();
using (var resStream = Resource.OpenResource("hitobject-combo-offset.osu"))
using (var stream = new StreamReader(resStream))
{
var beatmap = decoder.Decode(stream);
var converted = new CatchBeatmapConverter(beatmap).Convert();
new CatchBeatmapProcessor(converted).PreProcess();
new CatchBeatmapProcessor(converted).PostProcess();
Assert.AreEqual(4, ((IHasComboInformation)converted.HitObjects.ElementAt(0)).ComboIndex);
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(2)).ComboIndex);
Assert.AreEqual(5, ((IHasComboInformation)converted.HitObjects.ElementAt(4)).ComboIndex);
Assert.AreEqual(6, ((IHasComboInformation)converted.HitObjects.ElementAt(6)).ComboIndex);
Assert.AreEqual(11, ((IHasComboInformation)converted.HitObjects.ElementAt(8)).ComboIndex);
Assert.AreEqual(14, ((IHasComboInformation)converted.HitObjects.ElementAt(11)).ComboIndex);
} }
} }

View File

@ -1,4 +1,32 @@
osu file format v14 osu file format v14
[HitObjects] [HitObjects]
255,193,2170,49,0,0:0:0:0: // Circle with combo offset (3)
255,193,1000,49,0,0:0:0:0:
// Combo index = 4
// Slider with new combo followed by circle with no new combo
256,192,2000,12,0,2000,0:0:0:0:
255,193,3000,1,0,0:0:0:0:
// Combo index = 5
// Slider without new combo followed by circle with no new combo
256,192,4000,8,0,5000,0:0:0:0:
255,193,6000,1,0,0:0:0:0:
// Combo index = 5
// Slider without new combo followed by circle with new combo
256,192,7000,8,0,8000,0:0:0:0:
255,193,9000,5,0,0:0:0:0:
// Combo index = 6
// Slider with new combo and offset (1) followed by circle with new combo and offset (3)
256,192,10000,28,0,11000,0:0:0:0:
255,193,12000,53,0,0:0:0:0:
// Combo index = 11
// Slider with new combo and offset (2) followed by slider with no new combo followed by circle with no new combo
256,192,13000,44,0,14000,0:0:0:0:
256,192,15000,8,0,16000,0:0:0:0:
255,193,17000,1,0,0:0:0:0:
// Combo index = 14

View File

@ -198,6 +198,8 @@ namespace osu.Game.Database
try try
{ {
Logger.Log($"Importing {item}...", LoggingTarget.Database);
using (var write = ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes. using (var write = ContextFactory.GetForWrite()) // used to share a context for full import. keep in mind this will block all writes.
{ {
try try

View File

@ -463,7 +463,7 @@ namespace osu.Game
Schedule(() => notifications.Post(new SimpleNotification Schedule(() => notifications.Post(new SimpleNotification
{ {
Icon = entry.Level == LogLevel.Important ? FontAwesome.fa_exclamation_circle : FontAwesome.fa_bomb, Icon = entry.Level == LogLevel.Important ? FontAwesome.fa_exclamation_circle : FontAwesome.fa_bomb,
Text = entry.Message + (entry.Exception != null ? "\n\nThis error has been automatically reported to the devs." : string.Empty), Text = entry.Message + (entry.Exception != null && IsDeployedBuild ? "\n\nThis error has been automatically reported to the devs." : string.Empty),
})); }));
} }
else if (recentLogCount == short_term_display_limit) else if (recentLogCount == short_term_display_limit)

View File

@ -18,8 +18,17 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
{ {
} }
private bool forceNewCombo;
private int extraComboOffset;
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset) protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
{ {
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
forceNewCombo = false;
extraComboOffset = 0;
return new ConvertHit return new ConvertHit
{ {
X = position.X, X = position.X,
@ -30,6 +39,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples) protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
{ {
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
forceNewCombo = false;
extraComboOffset = 0;
return new ConvertSlider return new ConvertSlider
{ {
X = position.X, X = position.X,
@ -45,11 +60,14 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime) protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime)
{ {
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
// Their combo offset is still added to that next hitobject's combo index
forceNewCombo |= FormatVersion <= 8 || newCombo;
extraComboOffset += comboOffset;
return new ConvertSpinner return new ConvertSpinner
{ {
EndTime = endTime, EndTime = endTime
NewCombo = FirstObject || newCombo,
ComboOffset = comboOffset
}; };
} }

View File

@ -19,8 +19,17 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
{ {
} }
private bool forceNewCombo;
private int extraComboOffset;
protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset) protected override HitObject CreateHit(Vector2 position, bool newCombo, int comboOffset)
{ {
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
forceNewCombo = false;
extraComboOffset = 0;
return new ConvertHit return new ConvertHit
{ {
Position = position, Position = position,
@ -31,6 +40,12 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples) protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, List<Vector2> controlPoints, double length, CurveType curveType, int repeatCount, List<List<SampleInfo>> repeatSamples)
{ {
newCombo |= forceNewCombo;
comboOffset += extraComboOffset;
forceNewCombo = false;
extraComboOffset = 0;
return new ConvertSlider return new ConvertSlider
{ {
Position = position, Position = position,
@ -46,12 +61,15 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime) protected override HitObject CreateSpinner(Vector2 position, bool newCombo, int comboOffset, double endTime)
{ {
// Convert spinners don't create the new combo themselves, but force the next non-spinner hitobject to create a new combo
// Their combo offset is still added to that next hitobject's combo index
forceNewCombo |= FormatVersion <= 8 || newCombo;
extraComboOffset += comboOffset;
return new ConvertSpinner return new ConvertSpinner
{ {
Position = position, Position = position,
EndTime = endTime, EndTime = endTime
NewCombo = FormatVersion <= 8 || FirstObject || newCombo,
ComboOffset = comboOffset
}; };
} }

View File

@ -19,6 +19,8 @@ namespace osu.Game.Utils
private readonly List<Task> tasks = new List<Task>(); private readonly List<Task> tasks = new List<Task>();
private Exception lastException;
public RavenLogger(OsuGame game) public RavenLogger(OsuGame game)
{ {
raven.Release = game.Version; raven.Release = game.Version;
@ -29,8 +31,20 @@ namespace osu.Game.Utils
{ {
if (entry.Level < LogLevel.Verbose) return; if (entry.Level < LogLevel.Verbose) return;
if (entry.Exception != null) var exception = entry.Exception;
queuePendingTask(raven.CaptureAsync(new SentryEvent(entry.Exception)));
if (exception != null)
{
// since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports.
if (lastException != null &&
lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace))
{
return;
}
lastException = exception;
queuePendingTask(raven.CaptureAsync(new SentryEvent(exception)));
}
else else
raven.AddTrail(new Breadcrumb(entry.Target.ToString(), BreadcrumbType.Navigation) { Message = entry.Message }); raven.AddTrail(new Breadcrumb(entry.Target.ToString(), BreadcrumbType.Navigation) { Message = entry.Message });
}; };