1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 02:17:46 +08:00

Merge branch 'master' into stop-counting-to-score-after-fail

This commit is contained in:
Dean Herbert 2019-08-09 14:16:34 +09:00 committed by GitHub
commit 29870c773c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 519 additions and 365 deletions

View File

@ -62,7 +62,7 @@
<Reference Include="Java.Interop" /> <Reference Include="Java.Interop" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.731.1" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.807.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2019.807.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <summary> /// <summary>
/// Keep the same as last row. /// Keep the same as last row.
/// </summary> /// </summary>
ForceStack = 1 << 0, ForceStack = 1,
/// <summary> /// <summary>
/// Keep different from last row. /// Keep different from last row.

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -482,5 +482,17 @@ namespace osu.Game.Tests.Beatmaps.Formats
Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank); Assert.AreEqual(hitObjects[0].Samples[0].Bank, hitObjects[0].Samples[1].Bank);
} }
} }
[Test]
public void TestInvalidEventStillPasses()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var badResStream = TestResources.OpenResource("invalid-events.osu"))
using (var badStream = new StreamReader(badResStream))
{
Assert.DoesNotThrow(() => decoder.Decode(badStream));
}
}
} }
} }

View File

@ -0,0 +1,14 @@
osu file format v14
[Events]
bad,event,this,should,fail
//Background and Video events
0,0,"machinetop_background.jpg",0,0
//Break Periods
2,122474,140135
//Storyboard Layer 0 (Background)
this,is,also,bad
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Sound Samples

View File

@ -1,8 +1,11 @@
// 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 System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Timing;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -11,78 +14,172 @@ namespace osu.Game.Tests.Visual.Gameplay
[TestFixture] [TestFixture]
public class TestSceneBreakOverlay : OsuTestScene public class TestSceneBreakOverlay : OsuTestScene
{ {
private readonly BreakOverlay breakOverlay; public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(BreakOverlay),
};
private readonly TestBreakOverlay breakOverlay;
private readonly IReadOnlyList<BreakPeriod> testBreaks = new List<BreakPeriod>
{
new BreakPeriod
{
StartTime = 1000,
EndTime = 5000,
},
new BreakPeriod
{
StartTime = 6000,
EndTime = 13500,
},
};
public TestSceneBreakOverlay() public TestSceneBreakOverlay()
{ {
Child = breakOverlay = new BreakOverlay(true); Add(breakOverlay = new TestBreakOverlay(true));
AddStep("2s break", () => startBreak(2000));
AddStep("5s break", () => startBreak(5000));
AddStep("10s break", () => startBreak(10000));
AddStep("15s break", () => startBreak(15000));
AddStep("2s, 2s", startMultipleBreaks);
AddStep("0.5s, 0.7s, 1s, 2s", startAnotherMultipleBreaks);
} }
private void startBreak(double duration) [Test]
public void TestShowBreaks()
{ {
breakOverlay.Breaks = new List<BreakPeriod> setClock(false);
addShowBreakStep(2);
addShowBreakStep(5);
addShowBreakStep(15);
}
[Test]
public void TestNoEffectsBreak()
{
var shortBreak = new BreakPeriod { EndTime = 500 };
setClock(true);
loadBreaksStep("short break", new[] { shortBreak });
addBreakSeeks(shortBreak, false);
}
[Test]
public void TestMultipleBreaks()
{
setClock(true);
loadBreaksStep("multiple breaks", testBreaks);
foreach (var b in testBreaks)
addBreakSeeks(b, false);
}
[Test]
public void TestRewindBreaks()
{
setClock(true);
loadBreaksStep("multiple breaks", testBreaks);
foreach (var b in testBreaks.Reverse())
addBreakSeeks(b, true);
}
[Test]
public void TestSkipBreaks()
{
setClock(true);
loadBreaksStep("multiple breaks", testBreaks);
seekAndAssertBreak("seek to break start", testBreaks[1].StartTime, true);
AddAssert("is skipped to break #2", () => breakOverlay.CurrentBreakIndex == 1);
seekAndAssertBreak("seek to break middle", testBreaks[1].StartTime + testBreaks[1].Duration / 2, true);
seekAndAssertBreak("seek to break end", testBreaks[1].EndTime, false);
seekAndAssertBreak("seek to break after end", testBreaks[1].EndTime + 500, false);
}
private void addShowBreakStep(double seconds)
{
AddStep($"show '{seconds}s' break", () => breakOverlay.Breaks = new List<BreakPeriod>
{ {
new BreakPeriod new BreakPeriod
{ {
StartTime = Clock.CurrentTime, StartTime = Clock.CurrentTime,
EndTime = Clock.CurrentTime + duration, EndTime = Clock.CurrentTime + seconds * 1000,
} }
}; });
} }
private void startMultipleBreaks() private void setClock(bool useManual)
{ {
double currentTime = Clock.CurrentTime; AddStep($"set {(useManual ? "manual" : "realtime")} clock", () => breakOverlay.SwitchClock(useManual));
breakOverlay.Breaks = new List<BreakPeriod>
{
new BreakPeriod
{
StartTime = currentTime,
EndTime = currentTime + 2000,
},
new BreakPeriod
{
StartTime = currentTime + 4000,
EndTime = currentTime + 6000,
}
};
} }
private void startAnotherMultipleBreaks() private void loadBreaksStep(string breakDescription, IReadOnlyList<BreakPeriod> breaks)
{ {
double currentTime = Clock.CurrentTime; AddStep($"load {breakDescription}", () => breakOverlay.Breaks = breaks);
seekAndAssertBreak("seek back to 0", 0, false);
breakOverlay.Breaks = new List<BreakPeriod> }
{
new BreakPeriod // Duration is less than 650 - too short to appear private void addBreakSeeks(BreakPeriod b, bool isReversed)
{ {
StartTime = currentTime, if (isReversed)
EndTime = currentTime + 500, {
}, seekAndAssertBreak("seek to break after end", b.EndTime + 500, false);
new BreakPeriod seekAndAssertBreak("seek to break end", b.EndTime, false);
{ seekAndAssertBreak("seek to break middle", b.StartTime + b.Duration / 2, b.HasEffect);
StartTime = currentTime + 1500, seekAndAssertBreak("seek to break start", b.StartTime, b.HasEffect);
EndTime = currentTime + 2200, }
}, else
new BreakPeriod {
{ seekAndAssertBreak("seek to break start", b.StartTime, b.HasEffect);
StartTime = currentTime + 3200, seekAndAssertBreak("seek to break middle", b.StartTime + b.Duration / 2, b.HasEffect);
EndTime = currentTime + 4200, seekAndAssertBreak("seek to break end", b.EndTime, false);
}, seekAndAssertBreak("seek to break after end", b.EndTime + 500, false);
new BreakPeriod }
{ }
StartTime = currentTime + 5200,
EndTime = currentTime + 7200, private void seekAndAssertBreak(string seekStepDescription, double time, bool shouldBeBreak)
{
AddStep(seekStepDescription, () => breakOverlay.ManualClockTime = time);
AddAssert($"is{(!shouldBeBreak ? " not" : string.Empty)} break time", () =>
{
breakOverlay.ProgressTime();
return breakOverlay.IsBreakTime.Value == shouldBeBreak;
});
}
private class TestBreakOverlay : BreakOverlay
{
private readonly FramedClock framedManualClock;
private readonly ManualClock manualClock;
private IFrameBasedClock originalClock;
public new int CurrentBreakIndex => base.CurrentBreakIndex;
public double ManualClockTime
{
get => manualClock.CurrentTime;
set => manualClock.CurrentTime = value;
}
public TestBreakOverlay(bool letterboxing)
: base(letterboxing)
{
framedManualClock = new FramedClock(manualClock = new ManualClock());
ProcessCustomClock = false;
}
public void ProgressTime()
{
framedManualClock.ProcessFrame();
Update();
}
public void SwitchClock(bool setManual) => Clock = setManual ? framedManualClock : originalClock;
protected override void LoadComplete()
{
base.LoadComplete();
originalClock = Clock;
} }
};
} }
} }
} }

View File

@ -5,7 +5,7 @@
<PackageReference Include="DeepEqual" Version="2.0.0" /> <PackageReference Include="DeepEqual" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -7,7 +7,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.14.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>

View File

@ -5,7 +5,6 @@ using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using osu.Framework.IO.File; using osu.Framework.IO.File;
using osu.Framework.Logging;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
@ -290,8 +289,9 @@ namespace osu.Game.Beatmaps.Formats
string[] split = line.Split(','); string[] split = line.Split(',');
EventType type; EventType type;
if (!Enum.TryParse(split[0], out type)) if (!Enum.TryParse(split[0], out type))
throw new InvalidDataException($@"Unknown event type {split[0]}"); throw new InvalidDataException($@"Unknown event type: {split[0]}");
switch (type) switch (type)
{ {
@ -318,8 +318,6 @@ namespace osu.Game.Beatmaps.Formats
} }
private void handleTimingPoint(string line) private void handleTimingPoint(string line)
{
try
{ {
string[] split = line.Split(','); string[] split = line.Split(',');
@ -395,15 +393,6 @@ namespace osu.Game.Beatmaps.Formats
AutoGenerated = timingChange AutoGenerated = timingChange
}); });
} }
catch (FormatException)
{
Logger.Log("A timing point could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important);
}
catch (OverflowException)
{
Logger.Log("A timing point could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important);
}
}
private void handleTimingControlPoint(TimingControlPoint newPoint) private void handleTimingControlPoint(TimingControlPoint newPoint)
{ {

View File

@ -49,7 +49,7 @@ namespace osu.Game.Beatmaps.Formats
} }
catch (Exception e) catch (Exception e)
{ {
Logger.Error(e, $"Failed to process line \"{line}\" into {output}"); Logger.Log($"Failed to process line \"{line}\" into {output}: {e.Message}", LoggingTarget.Runtime, LogLevel.Important);
} }
} }
} }

View File

@ -82,8 +82,9 @@ namespace osu.Game.Beatmaps.Formats
storyboardSprite = null; storyboardSprite = null;
EventType type; EventType type;
if (!Enum.TryParse(split[0], out type)) if (!Enum.TryParse(split[0], out type))
throw new InvalidDataException($@"Unknown event type {split[0]}"); throw new InvalidDataException($@"Unknown event type: {split[0]}");
switch (type) switch (type)
{ {

View File

@ -9,7 +9,7 @@ namespace osu.Game.Beatmaps.Legacy
public enum LegacyMods public enum LegacyMods
{ {
None = 0, None = 0,
NoFail = 1 << 0, NoFail = 1,
Easy = 1 << 1, Easy = 1 << 1,
TouchDevice = 1 << 2, TouchDevice = 1 << 2,
Hidden = 1 << 3, Hidden = 1 << 3,

View File

@ -1,6 +1,8 @@
// 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 osu.Game.Screens.Play;
namespace osu.Game.Beatmaps.Timing namespace osu.Game.Beatmaps.Timing
{ {
public class BreakPeriod public class BreakPeriod
@ -35,6 +37,6 @@ namespace osu.Game.Beatmaps.Timing
/// </summary> /// </summary>
/// <param name="time">The time to check in milliseconds.</param> /// <param name="time">The time to check in milliseconds.</param>
/// <returns>Whether the time falls within this <see cref="BreakPeriod"/>.</returns> /// <returns>Whether the time falls within this <see cref="BreakPeriod"/>.</returns>
public bool Contains(double time) => time >= StartTime && time <= EndTime; public bool Contains(double time) => time >= StartTime && time <= EndTime - BreakOverlay.BREAK_FADE_DURATION;
} }
} }

View File

@ -31,10 +31,21 @@ namespace osu.Game.Database
/// </summary> /// </summary>
/// <typeparam name="TModel">The model type.</typeparam> /// <typeparam name="TModel">The model type.</typeparam>
/// <typeparam name="TFileModel">The associated file join type.</typeparam> /// <typeparam name="TFileModel">The associated file join type.</typeparam>
public abstract class ArchiveModelManager<TModel, TFileModel> : ArchiveModelManager, ICanAcceptFiles, IModelManager<TModel> public abstract class ArchiveModelManager<TModel, TFileModel> : ICanAcceptFiles, IModelManager<TModel>
where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete where TModel : class, IHasFiles<TFileModel>, IHasPrimaryKey, ISoftDelete
where TFileModel : INamedFileInfo, new() where TFileModel : INamedFileInfo, new()
{ {
private const int import_queue_request_concurrency = 1;
/// <summary>
/// A singleton scheduler shared by all <see cref="ArchiveModelManager{TModel,TFileModel}"/>.
/// </summary>
/// <remarks>
/// This scheduler generally performs IO and CPU intensive work so concurrency is limited harshly.
/// It is mainly being used as a queue mechanism for large imports.
/// </remarks>
private static readonly ThreadedTaskScheduler import_scheduler = new ThreadedTaskScheduler(import_queue_request_concurrency, nameof(ArchiveModelManager<TModel, TFileModel>));
/// <summary> /// <summary>
/// Set an endpoint for notifications to be posted to. /// Set an endpoint for notifications to be posted to.
/// </summary> /// </summary>
@ -336,7 +347,7 @@ namespace osu.Game.Database
flushEvents(true); flushEvents(true);
return item; return item;
}, cancellationToken, TaskCreationOptions.HideScheduler, IMPORT_SCHEDULER).Unwrap(); }, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap();
/// <summary> /// <summary>
/// Perform an update of the specified item. /// Perform an update of the specified item.
@ -646,18 +657,4 @@ namespace osu.Game.Database
#endregion #endregion
} }
public abstract class ArchiveModelManager
{
private const int import_queue_request_concurrency = 1;
/// <summary>
/// A singleton scheduler shared by all <see cref="ArchiveModelManager{TModel,TFileModel}"/>.
/// </summary>
/// <remarks>
/// This scheduler generally performs IO and CPU intensive work so concurrency is limited harshly.
/// It is mainly being used as a queue mechanism for large imports.
/// </remarks>
protected static readonly ThreadedTaskScheduler IMPORT_SCHEDULER = new ThreadedTaskScheduler(import_queue_request_concurrency, nameof(ArchiveModelManager));
}
} }

View File

@ -110,7 +110,7 @@ namespace osu.Game.Graphics.UserInterface
[Flags] [Flags]
public enum BarDirection public enum BarDirection
{ {
LeftToRight = 1 << 0, LeftToRight = 1,
RightToLeft = 1 << 1, RightToLeft = 1 << 1,
TopToBottom = 1 << 2, TopToBottom = 1 << 2,
BottomToTop = 1 << 3, BottomToTop = 1 << 3,

View File

@ -213,8 +213,27 @@ namespace osu.Game.Online.Chat
PostMessage(content, true); PostMessage(content, true);
break; break;
case "join":
if (string.IsNullOrWhiteSpace(content))
{
target.AddNewMessages(new ErrorMessage("Usage: /join [channel]"));
break;
}
var channel = availableChannels.Where(c => c.Name == content || c.Name == $"#{content}").FirstOrDefault();
if (channel == null)
{
target.AddNewMessages(new ErrorMessage($"Channel '{content}' not found."));
break;
}
JoinChannel(channel);
CurrentChannel.Value = channel;
break;
case "help": case "help":
target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action]")); target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel]"));
break; break;
default: default:

View File

@ -8,7 +8,7 @@ namespace osu.Game.Online.Chat
public ErrorMessage(string message) public ErrorMessage(string message)
: base(message) : base(message)
{ {
Sender.Colour = @"ff0000"; // todo: this should likely be styled differently in the future.
} }
} }
} }

View File

@ -10,7 +10,6 @@ using osu.Game.Beatmaps.Formats;
using osu.Game.Audio; using osu.Game.Audio;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Logging;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
namespace osu.Game.Rulesets.Objects.Legacy namespace osu.Game.Rulesets.Objects.Legacy
@ -40,8 +39,6 @@ namespace osu.Game.Rulesets.Objects.Legacy
[CanBeNull] [CanBeNull]
public override HitObject Parse(string text) public override HitObject Parse(string text)
{
try
{ {
string[] split = text.Split(','); string[] split = text.Split(',');
@ -219,10 +216,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
} }
if (result == null) if (result == null)
{ throw new InvalidDataException($"Unknown hit object type: {split[3]}");
Logger.Log($"Unknown hit object type: {type}. Skipped.", level: LogLevel.Error);
return null;
}
result.StartTime = startTime; result.StartTime = startTime;
@ -233,17 +227,6 @@ namespace osu.Game.Rulesets.Objects.Legacy
return result; return result;
} }
catch (FormatException)
{
Logger.Log("A hitobject could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important);
}
catch (OverflowException)
{
Logger.Log("A hitobject could not be parsed correctly and will be ignored", LoggingTarget.Runtime, LogLevel.Important);
}
return null;
}
private void readCustomSampleBanks(string str, SampleBankInfo bankInfo) private void readCustomSampleBanks(string str, SampleBankInfo bankInfo)
{ {

View File

@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
[Flags] [Flags]
internal enum ConvertHitObjectType internal enum ConvertHitObjectType
{ {
Circle = 1 << 0, Circle = 1,
Slider = 1 << 1, Slider = 1 << 1,
NewCombo = 1 << 2, NewCombo = 1 << 2,
Spinner = 1 << 3, Spinner = 1 << 3,

View File

@ -313,6 +313,9 @@ namespace osu.Game.Rulesets.Scoring
/// <summary> /// <summary>
/// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>. /// Applies the score change of a <see cref="JudgementResult"/> to this <see cref="ScoreProcessor"/>.
/// </summary> /// </summary>
/// <remarks>
/// Any changes applied via this method can be reverted via <see cref="RevertResult"/>.
/// </remarks>
/// <param name="result">The <see cref="JudgementResult"/> to apply.</param> /// <param name="result">The <see cref="JudgementResult"/> to apply.</param>
protected virtual void ApplyResult(JudgementResult result) protected virtual void ApplyResult(JudgementResult result)
{ {
@ -361,7 +364,7 @@ namespace osu.Game.Rulesets.Scoring
} }
/// <summary> /// <summary>
/// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/>. /// Reverts the score change of a <see cref="JudgementResult"/> that was applied to this <see cref="ScoreProcessor"/> via <see cref="ApplyResult"/>.
/// </summary> /// </summary>
/// <param name="result">The judgement scoring result.</param> /// <param name="result">The judgement scoring result.</param>
protected virtual void RevertResult(JudgementResult result) protected virtual void RevertResult(JudgementResult result)

View File

@ -1,9 +0,0 @@
// 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.
namespace osu.Game.Screens.Direct
{
public class OnlineListing : ScreenWhiteBox
{
}
}

View File

@ -14,7 +14,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Backgrounds;
using osu.Game.Screens.Charts; using osu.Game.Screens.Charts;
using osu.Game.Screens.Direct;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
using osu.Game.Screens.Multi; using osu.Game.Screens.Multi;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
@ -65,7 +64,6 @@ namespace osu.Game.Screens.Menu
buttons = new ButtonSystem buttons = new ButtonSystem
{ {
OnChart = delegate { this.Push(new ChartListing()); }, OnChart = delegate { this.Push(new ChartListing()); },
OnDirect = delegate { this.Push(new OnlineListing()); },
OnEdit = delegate { this.Push(new Editor()); }, OnEdit = delegate { this.Push(new Editor()); },
OnSolo = onSolo, OnSolo = onSolo,
OnMulti = delegate { this.Push(new Multiplayer()); }, OnMulti = delegate { this.Push(new Multiplayer()); },

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -15,7 +16,11 @@ namespace osu.Game.Screens.Play
{ {
public class BreakOverlay : Container public class BreakOverlay : Container
{ {
private const double fade_duration = BreakPeriod.MIN_BREAK_DURATION / 2; /// <summary>
/// The duration of the break overlay fading.
/// </summary>
public const double BREAK_FADE_DURATION = BreakPeriod.MIN_BREAK_DURATION / 2;
private const float remaining_time_container_max_size = 0.3f; private const float remaining_time_container_max_size = 0.3f;
private const int vertical_margin = 25; private const int vertical_margin = 25;
@ -29,12 +34,27 @@ namespace osu.Game.Screens.Play
set set
{ {
breaks = value; breaks = value;
// reset index in case the new breaks list is smaller than last one
isBreakTime.Value = false;
CurrentBreakIndex = 0;
if (IsLoaded)
initializeBreaks(); initializeBreaks();
} }
} }
public override bool RemoveCompletedTransforms => false; public override bool RemoveCompletedTransforms => false;
/// <summary>
/// Whether the gameplay is currently in a break.
/// </summary>
public IBindable<bool> IsBreakTime => isBreakTime;
protected int CurrentBreakIndex;
private readonly BindableBool isBreakTime = new BindableBool();
private readonly Container remainingTimeAdjustmentBox; private readonly Container remainingTimeAdjustmentBox;
private readonly Container remainingTimeBox; private readonly Container remainingTimeBox;
private readonly RemainingTimeCounter remainingTimeCounter; private readonly RemainingTimeCounter remainingTimeCounter;
@ -109,10 +129,36 @@ namespace osu.Game.Screens.Play
initializeBreaks(); initializeBreaks();
} }
protected override void Update()
{
base.Update();
updateBreakTimeBindable();
}
private void updateBreakTimeBindable()
{
if (breaks == null || breaks.Count == 0)
return;
var time = Clock.CurrentTime;
if (time > breaks[CurrentBreakIndex].EndTime)
{
while (time > breaks[CurrentBreakIndex].EndTime && CurrentBreakIndex < breaks.Count - 1)
CurrentBreakIndex++;
}
else
{
while (time < breaks[CurrentBreakIndex].StartTime && CurrentBreakIndex > 0)
CurrentBreakIndex--;
}
var currentBreak = breaks[CurrentBreakIndex];
isBreakTime.Value = currentBreak.HasEffect && currentBreak.Contains(time);
}
private void initializeBreaks() private void initializeBreaks()
{ {
if (!IsLoaded) return; // we need a clock.
FinishTransforms(true); FinishTransforms(true);
Scheduler.CancelDelayedTasks(); Scheduler.CancelDelayedTasks();
@ -125,25 +171,25 @@ namespace osu.Game.Screens.Play
using (BeginAbsoluteSequence(b.StartTime, true)) using (BeginAbsoluteSequence(b.StartTime, true))
{ {
fadeContainer.FadeIn(fade_duration); fadeContainer.FadeIn(BREAK_FADE_DURATION);
breakArrows.Show(fade_duration); breakArrows.Show(BREAK_FADE_DURATION);
remainingTimeAdjustmentBox remainingTimeAdjustmentBox
.ResizeWidthTo(remaining_time_container_max_size, fade_duration, Easing.OutQuint) .ResizeWidthTo(remaining_time_container_max_size, BREAK_FADE_DURATION, Easing.OutQuint)
.Delay(b.Duration - fade_duration) .Delay(b.Duration - BREAK_FADE_DURATION)
.ResizeWidthTo(0); .ResizeWidthTo(0);
remainingTimeBox remainingTimeBox
.ResizeWidthTo(0, b.Duration - fade_duration) .ResizeWidthTo(0, b.Duration - BREAK_FADE_DURATION)
.Then() .Then()
.ResizeWidthTo(1); .ResizeWidthTo(1);
remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration); remainingTimeCounter.CountTo(b.Duration).CountTo(0, b.Duration);
using (BeginDelayedSequence(b.Duration - fade_duration, true)) using (BeginDelayedSequence(b.Duration - BREAK_FADE_DURATION, true))
{ {
fadeContainer.FadeOut(fade_duration); fadeContainer.FadeOut(BREAK_FADE_DURATION);
breakArrows.Hide(fade_duration); breakArrows.Hide(BREAK_FADE_DURATION);
} }
} }
} }

View File

@ -66,6 +66,8 @@ namespace osu.Game.Screens.Play
private SampleChannel sampleRestart; private SampleChannel sampleRestart;
private BreakOverlay breakOverlay;
protected ScoreProcessor ScoreProcessor { get; private set; } protected ScoreProcessor ScoreProcessor { get; private set; }
protected DrawableRuleset DrawableRuleset { get; private set; } protected DrawableRuleset DrawableRuleset { get; private set; }
@ -134,7 +136,7 @@ namespace osu.Game.Screens.Play
} }
} }
}, },
new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor) breakOverlay = new BreakOverlay(working.Beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
@ -411,8 +413,7 @@ namespace osu.Game.Screens.Play
PauseOverlay.Hide(); PauseOverlay.Hide();
// breaks and time-based conditions may allow instant resume. // breaks and time-based conditions may allow instant resume.
double time = GameplayClockContainer.GameplayClock.CurrentTime; if (breakOverlay.IsBreakTime.Value || GameplayClockContainer.GameplayClock.CurrentTime < Beatmap.Value.Beatmap.HitObjects.First().StartTime)
if (Beatmap.Value.Beatmap.Breaks.Any(b => b.Contains(time)) || time < Beatmap.Value.Beatmap.HitObjects.First().StartTime)
completeResume(); completeResume();
else else
DrawableRuleset.RequestResume(completeResume); DrawableRuleset.RequestResume(completeResume);

View File

@ -187,6 +187,7 @@ namespace osu.Game.Users
public static readonly User SYSTEM_USER = new User public static readonly User SYSTEM_USER = new User
{ {
Username = "system", Username = "system",
Colour = @"9c0101",
Id = 0 Id = 0
}; };

View File

@ -14,7 +14,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.731.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.807.0" /> <PackageReference Include="ppy.osu.Framework" Version="2019.807.0" />
<PackageReference Include="SharpCompress" Version="0.23.0" /> <PackageReference Include="SharpCompress" Version="0.23.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />

View File

@ -104,7 +104,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.702.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.731.1" />
<PackageReference Include="ppy.osu.Framework" Version="2019.807.0" /> <PackageReference Include="ppy.osu.Framework" Version="2019.807.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.807.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2019.807.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" /> <PackageReference Include="SharpCompress" Version="0.22.0" />