diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs index e5bcc08924..ede89c6096 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatSyncedContainer.cs @@ -135,6 +135,35 @@ namespace osu.Game.Tests.Visual.UserInterface AddAssert("bpm is default", () => lastBpm != null && Precision.AlmostEquals(lastBpm.Value, 60)); } + [TestCase(true)] + [TestCase(false)] + public void TestEarlyActivationEffectPoint(bool earlyActivating) + { + double earlyActivationMilliseconds = earlyActivating ? 100 : 0; + ControlPoint actualEffectPoint = null; + + AddStep($"set early activation to {earlyActivationMilliseconds}", () => beatContainer.EarlyActivationMilliseconds = earlyActivationMilliseconds); + + AddStep("seek before kiai effect point", () => + { + ControlPoint expectedEffectPoint = Beatmap.Value.Beatmap.ControlPointInfo.EffectPoints.First(ep => ep.KiaiMode); + actualEffectPoint = null; + beatContainer.AllowMistimedEventFiring = false; + + beatContainer.NewBeat = (i, timingControlPoint, effectControlPoint, channelAmplitudes) => + { + if (Precision.AlmostEquals(gameplayClockContainer.CurrentTime + earlyActivationMilliseconds, expectedEffectPoint.Time, BeatSyncedContainer.MISTIMED_ALLOWANCE)) + actualEffectPoint = effectControlPoint; + }; + + gameplayClockContainer.Seek(expectedEffectPoint.Time - earlyActivationMilliseconds); + }); + + AddUntilStep("wait for effect point", () => actualEffectPoint != null); + + AddAssert("effect has kiai", () => actualEffectPoint != null && ((EffectControlPoint)actualEffectPoint).KiaiMode); + } + private class TestBeatSyncedContainer : BeatSyncedContainer { private const int flash_layer_height = 150; @@ -145,6 +174,12 @@ namespace osu.Game.Tests.Visual.UserInterface set => base.AllowMistimedEventFiring = value; } + public new double EarlyActivationMilliseconds + { + get => base.EarlyActivationMilliseconds; + set => base.EarlyActivationMilliseconds = value; + } + private readonly InfoString timingPointCount; private readonly InfoString currentTimingPoint; private readonly InfoString beatCount; diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs index 6e4901ab1a..2024d18570 100644 --- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs +++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs @@ -111,7 +111,7 @@ namespace osu.Game.Graphics.Containers if (clock == null) return; - double currentTrackTime = clock.CurrentTime; + double currentTrackTime = clock.CurrentTime + EarlyActivationMilliseconds; if (Beatmap.Value.TrackLoaded && Beatmap.Value.BeatmapLoaded) { @@ -132,13 +132,11 @@ namespace osu.Game.Graphics.Containers { // this may be the case where the beat syncing clock has been paused. // we still want to show an idle animation, so use this container's time instead. - currentTrackTime = Clock.CurrentTime; + currentTrackTime = Clock.CurrentTime + EarlyActivationMilliseconds; timingPoint = TimingControlPoint.DEFAULT; effectPoint = EffectControlPoint.DEFAULT; } - currentTrackTime += EarlyActivationMilliseconds; - double beatLength = timingPoint.BeatLength / Divisor; while (beatLength < MinimumBeatLength)