diff --git a/osu.Game/Rulesets/UI/HitRenderer.cs b/osu.Game/Rulesets/UI/HitRenderer.cs index a3a806b6a7..25d8bae205 100644 --- a/osu.Game/Rulesets/UI/HitRenderer.cs +++ b/osu.Game/Rulesets/UI/HitRenderer.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.UI where TObject : HitObject { /// - /// The Beatmap + /// The Beatmap /// public Beatmap Beatmap; diff --git a/osu.Game/Screens/Play/PlayerInputManager.cs b/osu.Game/Screens/Play/PlayerInputManager.cs index 3ac28898a6..c6853b3007 100644 --- a/osu.Game/Screens/Play/PlayerInputManager.cs +++ b/osu.Game/Screens/Play/PlayerInputManager.cs @@ -36,6 +36,38 @@ namespace osu.Game.Screens.Play Clock = new FramedClock(clock); } + /// + /// Whether we running up-to-date with our parent clock. + /// If not, we will need to keep processing children until we catch up. + /// + private bool requireMoreUpdateLoops; + + /// + /// Whether we in a valid state (ie. should we keep processing children frames). + /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. + /// + private bool validState; + + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; + + private bool isAttached => replayInputHandler != null && !UseParentState; + + private const int max_catch_up_updates_per_frame = 50; + + public override bool UpdateSubTree() + { + requireMoreUpdateLoops = true; + validState = true; + + int loops = 0; + + while (validState && requireMoreUpdateLoops && loops++ < 50) + if (!base.UpdateSubTree()) + return false; + + return true; + } + protected override void Update() { if (parentClock == null) return; @@ -43,28 +75,26 @@ namespace osu.Game.Screens.Play clock.Rate = parentClock.Rate; clock.IsRunning = parentClock.IsRunning; - //if a replayHandler is not attached, we should just pass-through. - if (UseParentState || replayInputHandler == null) + if (!isAttached) { clock.CurrentTime = parentClock.CurrentTime; - base.Update(); - return; } - - while (true) + else { double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime); if (newTime == null) - //we shouldn't execute for this time value - break; - - if (clock.CurrentTime == parentClock.CurrentTime) - break; + { + // we shouldn't execute for this time value. probably waiting on more replay data. + validState = false; + return; + } clock.CurrentTime = newTime.Value; - base.Update(); } + + requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime; + base.Update(); } } }