mirror of
https://github.com/ppy/osu.git
synced 2024-12-16 03:02:53 +08:00
Merge branch 'master' into relax
This commit is contained in:
commit
6a4ff19c90
@ -4,7 +4,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
|
using osu.Framework.Development;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
|
|
||||||
@ -20,6 +24,8 @@ namespace osu.Desktop
|
|||||||
|
|
||||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
||||||
{
|
{
|
||||||
|
host.ExceptionThrown += handleException;
|
||||||
|
|
||||||
if (!host.IsPrimaryInstance)
|
if (!host.IsPrimaryInstance)
|
||||||
{
|
{
|
||||||
var importer = new ArchiveImportIPCChannel(host);
|
var importer = new ArchiveImportIPCChannel(host);
|
||||||
@ -45,5 +51,24 @@ namespace osu.Desktop
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int allowableExceptions = DebugUtils.IsDebugBuild ? 0 : 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allow a maximum of one unhandled exception, per second of execution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="arg"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static bool handleException(Exception arg)
|
||||||
|
{
|
||||||
|
bool continueExecution = Interlocked.Decrement(ref allowableExceptions) >= 0;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
return continueExecution;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,6 +286,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
|
/// <returns>The <see cref="Pattern"/> containing the hit objects.</returns>
|
||||||
private Pattern generateRandomPatternWithMirrored(double centreProbability, double p2, double p3)
|
private Pattern generateRandomPatternWithMirrored(double centreProbability, double p2, double p3)
|
||||||
{
|
{
|
||||||
|
if (convertType.HasFlag(PatternType.ForceNotStack))
|
||||||
|
return generateRandomPattern(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3);
|
||||||
|
|
||||||
var pattern = new Pattern();
|
var pattern = new Pattern();
|
||||||
|
|
||||||
bool addToCentre;
|
bool addToCentre;
|
||||||
@ -370,9 +373,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
{
|
{
|
||||||
addToCentre = false;
|
addToCentre = false;
|
||||||
|
|
||||||
if (convertType.HasFlag(PatternType.ForceNotStack))
|
|
||||||
return getRandomNoteCount(1 / 2f + p2 / 2, p2, (p2 + p3) / 2, p3);
|
|
||||||
|
|
||||||
switch (TotalColumns)
|
switch (TotalColumns)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -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.
|
||||||
@ -55,15 +57,18 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
{
|
{
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
|
|
||||||
while (condition() && iterations++ < max_rng_iterations)
|
while (condition())
|
||||||
action();
|
{
|
||||||
|
if (iterations++ >= max_rng_iterations)
|
||||||
if (iterations < max_rng_iterations)
|
{
|
||||||
|
// log an error but don't throw. we want to continue execution.
|
||||||
|
Logger.Error(new ExceededAllowedIterationsException(new StackTrace(0)),
|
||||||
|
"Conversion encountered errors. The beatmap may not be correctly converted.");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate + log an error/stacktrace
|
action();
|
||||||
|
}
|
||||||
Logger.Log($"Allowable iterations ({max_rng_iterations}) exceeded:\n{new StackTrace(0)}", level: LogLevel.Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -71,5 +76,21 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
/// <returns>The <see cref="Pattern"/>s containing the hit objects.</returns>
|
||||||
public abstract IEnumerable<Pattern> Generate();
|
public abstract IEnumerable<Pattern> Generate();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Denotes when a single conversion operation is in an infinitely looping state.
|
||||||
|
/// </summary>
|
||||||
|
public class ExceededAllowedIterationsException : Exception
|
||||||
|
{
|
||||||
|
private readonly string stackTrace;
|
||||||
|
|
||||||
|
public ExceededAllowedIterationsException(StackTrace stackTrace)
|
||||||
|
{
|
||||||
|
this.stackTrace = stackTrace.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string StackTrace => stackTrace;
|
||||||
|
public override string ToString() => $"{GetType().Name}: {Message}\r\n{StackTrace}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
@ -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
|
||||||
|
@ -36,6 +36,8 @@ using osu.Game.Skinning;
|
|||||||
using OpenTK.Graphics;
|
using OpenTK.Graphics;
|
||||||
using osu.Game.Overlays.Volume;
|
using osu.Game.Overlays.Volume;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
|
using osu.Game.Utils;
|
||||||
|
using LogLevel = osu.Framework.Logging.LogLevel;
|
||||||
|
|
||||||
namespace osu.Game
|
namespace osu.Game
|
||||||
{
|
{
|
||||||
@ -65,6 +67,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
private ScreenshotManager screenshotManager;
|
private ScreenshotManager screenshotManager;
|
||||||
|
|
||||||
|
protected RavenLogger RavenLogger;
|
||||||
|
|
||||||
public virtual Storage GetStorageForStableInstall() => null;
|
public virtual Storage GetStorageForStableInstall() => null;
|
||||||
|
|
||||||
private Intro intro
|
private Intro intro
|
||||||
@ -108,6 +112,8 @@ namespace osu.Game
|
|||||||
this.args = args;
|
this.args = args;
|
||||||
|
|
||||||
forwardLoggedErrorsToNotifications();
|
forwardLoggedErrorsToNotifications();
|
||||||
|
|
||||||
|
RavenLogger = new RavenLogger(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleSettings() => settings.ToggleVisibility();
|
public void ToggleSettings() => settings.ToggleVisibility();
|
||||||
@ -145,13 +151,15 @@ namespace osu.Game
|
|||||||
|
|
||||||
if (args?.Length > 0)
|
if (args?.Length > 0)
|
||||||
{
|
{
|
||||||
var paths = args.Where(a => !a.StartsWith(@"-"));
|
var paths = args.Where(a => !a.StartsWith(@"-")).ToArray();
|
||||||
|
if (paths.Length > 0)
|
||||||
Task.Run(() => Import(paths.ToArray()));
|
Task.Run(() => Import(paths));
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies.CacheAs(this);
|
dependencies.CacheAs(this);
|
||||||
|
|
||||||
|
dependencies.Cache(RavenLogger);
|
||||||
|
|
||||||
dependencies.CacheAs(ruleset);
|
dependencies.CacheAs(ruleset);
|
||||||
dependencies.CacheAs<IBindable<RulesetInfo>>(ruleset);
|
dependencies.CacheAs<IBindable<RulesetInfo>>(ruleset);
|
||||||
|
|
||||||
@ -273,6 +281,12 @@ namespace osu.Game
|
|||||||
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
|
menu.Push(new PlayerLoader(new ReplayPlayer(s.Replay)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
RavenLogger.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
// this needs to be cached before base.LoadComplete as it is used by MenuCursorContainer.
|
// this needs to be cached before base.LoadComplete as it is used by MenuCursorContainer.
|
||||||
@ -449,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,
|
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)
|
||||||
@ -601,6 +615,7 @@ namespace osu.Game
|
|||||||
private void screenAdded(Screen newScreen)
|
private void screenAdded(Screen newScreen)
|
||||||
{
|
{
|
||||||
currentScreen = (OsuScreen)newScreen;
|
currentScreen = (OsuScreen)newScreen;
|
||||||
|
Logger.Log($"Screen changed → {currentScreen}");
|
||||||
|
|
||||||
newScreen.ModePushed += screenAdded;
|
newScreen.ModePushed += screenAdded;
|
||||||
newScreen.Exited += screenRemoved;
|
newScreen.Exited += screenRemoved;
|
||||||
@ -609,6 +624,7 @@ namespace osu.Game
|
|||||||
private void screenRemoved(Screen newScreen)
|
private void screenRemoved(Screen newScreen)
|
||||||
{
|
{
|
||||||
currentScreen = (OsuScreen)newScreen;
|
currentScreen = (OsuScreen)newScreen;
|
||||||
|
Logger.Log($"Screen changed ← {currentScreen}");
|
||||||
|
|
||||||
if (newScreen == null)
|
if (newScreen == null)
|
||||||
Exit();
|
Exit();
|
||||||
|
@ -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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
89
osu.Game/Utils/RavenLogger.cs
Normal file
89
osu.Game/Utils/RavenLogger.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using osu.Framework.Logging;
|
||||||
|
using SharpRaven;
|
||||||
|
using SharpRaven.Data;
|
||||||
|
|
||||||
|
namespace osu.Game.Utils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Report errors to sentry.
|
||||||
|
/// </summary>
|
||||||
|
public class RavenLogger : IDisposable
|
||||||
|
{
|
||||||
|
private readonly RavenClient raven = new RavenClient("https://5e342cd55f294edebdc9ad604d28bbd3@sentry.io/1255255");
|
||||||
|
|
||||||
|
private readonly List<Task> tasks = new List<Task>();
|
||||||
|
|
||||||
|
private Exception lastException;
|
||||||
|
|
||||||
|
public RavenLogger(OsuGame game)
|
||||||
|
{
|
||||||
|
raven.Release = game.Version;
|
||||||
|
|
||||||
|
if (!game.IsDeployedBuild) return;
|
||||||
|
|
||||||
|
Logger.NewEntry += entry =>
|
||||||
|
{
|
||||||
|
if (entry.Level < LogLevel.Verbose) return;
|
||||||
|
|
||||||
|
var exception = 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
|
||||||
|
raven.AddTrail(new Breadcrumb(entry.Target.ToString(), BreadcrumbType.Navigation) { Message = entry.Message });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queuePendingTask(Task<string> task)
|
||||||
|
{
|
||||||
|
lock (tasks) tasks.Add(task);
|
||||||
|
task.ContinueWith(_ =>
|
||||||
|
{
|
||||||
|
lock (tasks)
|
||||||
|
tasks.Remove(task);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Disposal
|
||||||
|
|
||||||
|
~RavenLogger()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isDisposed;
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
if (isDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
isDisposed = true;
|
||||||
|
lock (tasks) Task.WaitAll(tasks.ToArray(), 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@
|
|||||||
<PackageReference Include="ppy.osu.Framework" Version="2018.815.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2018.815.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
<PackageReference Include="SharpCompress" Version="0.22.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.10.1" />
|
<PackageReference Include="NUnit" Version="3.10.1" />
|
||||||
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
Loading…
Reference in New Issue
Block a user