1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 02:43:19 +08:00

Merge pull request #24448 from peppy/multi-spectator-better-start-time

Improve choice of where to start playback of multiplayer spectator
This commit is contained in:
Bartłomiej Dach 2023-08-03 22:42:09 +02:00 committed by GitHub
commit 270c03235d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 25 additions and 9 deletions

View File

@ -2,12 +2,13 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Game.Graphics;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
@ -198,15 +199,29 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
private void performInitialSeek()
{
// Seek the master clock to the gameplay time.
// This is chosen as the first available frame in the players' replays, which matches the seek by each individual SpectatorPlayer.
double startTime = instances.Where(i => i.Score != null)
.SelectMany(i => i.Score.AsNonNull().Replay.Frames)
.Select(f => f.Time)
.DefaultIfEmpty(0)
.Min();
// We want to start showing gameplay as soon as possible.
// Each client may be in a different place in the beatmap, so we need to do our best to find a common
// starting point.
//
// Preferring a lower value ensures that we don't have some clients stuttering to keep up.
List<double> minFrameTimes = new List<double>();
foreach (var instance in instances)
{
if (instance.Score == null)
continue;
minFrameTimes.Add(instance.Score.Replay.Frames.MinBy(f => f.Time)?.Time ?? 0);
}
// Remove any outliers (only need to worry about removing those lower than the mean since we will take a Min() after).
double mean = minFrameTimes.Average();
minFrameTimes.RemoveAll(t => mean - t > 1000);
double startTime = minFrameTimes.Min();
masterClockContainer.Reset(startTime, true);
Logger.Log($"Multiplayer spectator seeking to initial time of {startTime}");
}
protected override void OnNewPlayingUserState(int userId, SpectatorState spectatorState)
@ -245,6 +260,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
return base.OnBackButton();
// On a manual exit, set the player back to idle unless gameplay has finished.
// Of note, this doesn't cover exiting using alt-f4 or menu home option.
if (multiplayerClient.Room.State != MultiplayerRoomState.Open)
multiplayerClient.ChangeState(MultiplayerUserState.Idle);

View File

@ -182,7 +182,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
return;
masterState = newState;
Logger.Log($"{nameof(SpectatorSyncManager)}'s master clock become {masterState}");
Logger.Log($"{nameof(SpectatorSyncManager)}'s master clock became {masterState}");
switch (masterState)
{