1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-21 08:12:56 +08:00

Add ability to disable mistimed event firings

This commit is contained in:
Dean Herbert 2021-07-15 16:13:13 +09:00
parent 3197f599bb
commit b6996d647e
2 changed files with 45 additions and 9 deletions

View File

@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface
[TestFixture] [TestFixture]
public class TestSceneBeatSyncedContainer : OsuTestScene public class TestSceneBeatSyncedContainer : OsuTestScene
{ {
private BeatContainer beatContainer; private TestBeatSyncedContainer beatContainer;
private MasterGameplayClockContainer gameplayClockContainer; private MasterGameplayClockContainer gameplayClockContainer;
@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{ {
gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, 0) gameplayClockContainer = new MasterGameplayClockContainer(Beatmap.Value, 0)
{ {
Child = beatContainer = new BeatContainer Child = beatContainer = new TestBeatSyncedContainer
{ {
Anchor = Anchor.BottomCentre, Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
@ -55,13 +55,16 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("Start playback", () => gameplayClockContainer.Start()); AddStep("Start playback", () => gameplayClockContainer.Start());
} }
[Test] [TestCase(false)]
public void TestSeekBackDoesntPlayMidBeat() [TestCase(true)]
public void TestDisallowMistimedEventFiring(bool allowMistimed)
{ {
int? lastBeatIndex = null; int? lastBeatIndex = null;
double? lastActuationTime = null; double? lastActuationTime = null;
TimingControlPoint lastTimingPoint = null; TimingControlPoint lastTimingPoint = null;
AddStep("set mistimed to disallow", () => beatContainer.AllowMistimedEventFiring = allowMistimed);
AddStep("bind event", () => AddStep("bind event", () =>
{ {
beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) =>
@ -79,7 +82,15 @@ namespace osu.Game.Tests.Visual.UserInterface
}); });
AddUntilStep("wait for trigger", () => lastBeatIndex != null); AddUntilStep("wait for trigger", () => lastBeatIndex != null);
AddAssert("trigger is near beat length", () => lastActuationTime != null && lastBeatIndex != null && Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, 32));
if (!allowMistimed)
{
AddAssert("trigger is near beat length", () => lastActuationTime != null && lastBeatIndex != null && Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE));
}
else
{
AddAssert("trigger is not near beat length", () => lastActuationTime != null && lastBeatIndex != null && !Precision.AlmostEquals(lastTimingPoint.Time + lastBeatIndex.Value * lastTimingPoint.BeatLength, lastActuationTime.Value, BeatSyncedContainer.MISTIMED_ALLOWANCE));
}
} }
[Test] [Test]
@ -132,10 +143,16 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("bpm is from beatmap", () => lastBpm != null && Precision.AlmostEquals(lastBpm.Value, 60)); AddAssert("bpm is from beatmap", () => lastBpm != null && Precision.AlmostEquals(lastBpm.Value, 60));
} }
private class BeatContainer : BeatSyncedContainer private class TestBeatSyncedContainer : BeatSyncedContainer
{ {
private const int flash_layer_height = 150; private const int flash_layer_height = 150;
public new bool AllowMistimedEventFiring
{
get => base.AllowMistimedEventFiring;
set => base.AllowMistimedEventFiring = value;
}
private readonly InfoString timingPointCount; private readonly InfoString timingPointCount;
private readonly InfoString currentTimingPoint; private readonly InfoString currentTimingPoint;
private readonly InfoString beatCount; private readonly InfoString beatCount;
@ -148,7 +165,7 @@ namespace osu.Game.Tests.Visual.UserInterface
private readonly Box flashLayer; private readonly Box flashLayer;
public BeatContainer() public TestBeatSyncedContainer()
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;

View File

@ -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.Diagnostics; using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
@ -35,6 +36,19 @@ namespace osu.Game.Graphics.Containers
/// </summary> /// </summary>
protected double EarlyActivationMilliseconds; protected double EarlyActivationMilliseconds;
/// <summary>
/// While this container automatically applied an animation delay (meaning any animations inside a <see cref="OnNewBeat"/> implementation will
/// always be correctly timed), the event itself can potentially fire away from the related beat.
///
/// By setting this to false, cases where the event is to be fired more than <see cref="MISTIMED_ALLOWANCE"/> from the related beat will be skipped.
/// </summary>
protected bool AllowMistimedEventFiring = true;
/// <summary>
/// The maximum deviance from the actual beat that an <see cref="OnNewBeat"/> can fire when <see cref="AllowMistimedEventFiring"/> is set to false.
/// </summary>
public const double MISTIMED_ALLOWANCE = 16;
/// <summary> /// <summary>
/// The time in milliseconds until the next beat. /// The time in milliseconds until the next beat.
/// </summary> /// </summary>
@ -145,8 +159,13 @@ namespace osu.Game.Graphics.Containers
if (timingPoint == lastTimingPoint && beatIndex == lastBeat) if (timingPoint == lastTimingPoint && beatIndex == lastBeat)
return; return;
// as this event is sometimes used for sound triggers where `BeginDelayedSequence` has no effect, avoid firing it if too far away from the beat.
// this can happen after a seek operation.
if (AllowMistimedEventFiring || Math.Abs(TimeSinceLastBeat) < MISTIMED_ALLOWANCE)
{
using (BeginDelayedSequence(-TimeSinceLastBeat)) using (BeginDelayedSequence(-TimeSinceLastBeat))
OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? ChannelAmplitudes.Empty); OnNewBeat(beatIndex, timingPoint, effectPoint, track?.CurrentAmplitudes ?? ChannelAmplitudes.Empty);
}
lastBeat = beatIndex; lastBeat = beatIndex;
lastTimingPoint = timingPoint; lastTimingPoint = timingPoint;