-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Fix multiplayer spectator potentially taking too long to start #24451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
When watching from the middle of gameplay, due to a series of failures, `SpectatorClock` would not get seeked to the current time, causing all clients to look like they were out of sync. This is a hotfix for the issue. A better fix will require framework changes or considerable restructuring. I'd recommend testing this works in practice and agreeing that while it is a hack, it's likely not going to cause issues and is something we want to see fixed sooner rather than later.
// | ||
// This breaks in multiplayer spectator. | ||
// I hope to remove this once we knock some sense into clocks in general. | ||
(SourceClock as IAdjustableClock)?.Seek(StartTime); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here's a "fun" question. This is preceded by a call to Seek()
, which is:
osu/osu.Game/Screens/Play/GameplayClockContainer.cs
Lines 117 to 128 in 9da1de8
/// <summary> | |
/// Seek to a specific time in gameplay. | |
/// </summary> | |
/// <param name="time">The destination time to seek to.</param> | |
public virtual void Seek(double time) | |
{ | |
Logger.Log($"{nameof(GameplayClockContainer)} seeking to {time}"); | |
GameplayClock.Seek(time); | |
OnSeek?.Invoke(); | |
} |
Which in turn calls
osu/osu.Game/Beatmaps/FramedBeatmapClock.cs
Lines 186 to 192 in 9da1de8
public bool Seek(double position) | |
{ | |
bool success = decoupledClock.Seek(position - TotalAppliedOffset); | |
finalClockSource.ProcessFrame(); | |
return success; | |
} |
Uh oh. Now there's offsets and decoupled interpolations and so on. The offsets worry me especially. It appears that in standard gameplay this currently seems to be partially saved by (a) the fact that the clock initially stops, which gets rid of the interpolation, and (b) the fact that offsets are applied in LoadComplete()
and so they're zero at the point where Reset()
is currently called, which is:
osu/osu.Game/Beatmaps/FramedBeatmapClock.cs
Lines 101 to 121 in 9da1de8
protected override void LoadComplete() | |
{ | |
base.LoadComplete(); | |
if (applyOffsets) | |
{ | |
Debug.Assert(userBeatmapOffsetClock != null); | |
Debug.Assert(userGlobalOffsetClock != null); | |
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset); | |
userAudioOffset.BindValueChanged(offset => userGlobalOffsetClock.Offset = offset.NewValue, true); | |
beatmapOffsetSubscription = realm.SubscribeToPropertyChanged( | |
r => r.Find<BeatmapInfo>(beatmap.Value.BeatmapInfo.ID)?.UserSettings, | |
settings => settings.Offset, | |
val => | |
{ | |
userBeatmapOffsetClock.Offset = val; | |
}); | |
} | |
} |
but in editor gameplay test I can get this log to trigger:
diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs
index 226108209a..70d4e17110 100644
--- a/osu.Game/Screens/Play/GameplayClockContainer.cs
+++ b/osu.Game/Screens/Play/GameplayClockContainer.cs
@@ -167,6 +167,9 @@ public void Reset(double? time = null, bool startClock = false)
// I hope to remove this once we knock some sense into clocks in general.
(SourceClock as IAdjustableClock)?.Seek(StartTime);
+ if (SourceClock.CurrentTime != CurrentTime)
+ Logger.Log($"UH OH WE DID A DESYNC. gcc is {CurrentTime}, source is {SourceClock.CurrentTime}");
+
if (!wasPaused || startClock)
Start();
}
Am I thinking correctly that this is a potential desync? And if so, then maybe just for sheer safety this should be
diff --git a/osu.Game/Screens/Play/GameplayClockContainer.cs b/osu.Game/Screens/Play/GameplayClockContainer.cs
index 226108209a..35e1e0b792 100644
--- a/osu.Game/Screens/Play/GameplayClockContainer.cs
+++ b/osu.Game/Screens/Play/GameplayClockContainer.cs
@@ -165,7 +165,7 @@ public void Reset(double? time = null, bool startClock = false)
//
// This breaks in multiplayer spectator.
// I hope to remove this once we knock some sense into clocks in general.
- (SourceClock as IAdjustableClock)?.Seek(StartTime);
+ (SourceClock as IAdjustableClock)?.Seek(CurrentTime);
if (!wasPaused || startClock)
Start();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes sense. I've updated the workaround and comment to hopefully explain this requirement.
When watching from the middle of gameplay, due to a series of failures,
SpectatorClock
would not get seeked to the current time, causing all clients to look like they were out of sync.This is a hotfix for the issue. A better fix will require framework changes or considerable restructuring.
I'd recommend testing this works in practice and agreeing that while it is a hack, it's likely not going to cause issues and is something we want to see fixed sooner rather than later.
Closes #22091.