1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 14:32:55 +08:00

Pause master clock when too far ahead

This commit is contained in:
smoogipoo 2021-06-11 19:15:53 +09:00
parent 59eda70c12
commit 0a8daab4f7
5 changed files with 71 additions and 5 deletions

View File

@ -103,6 +103,23 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddWaitStep("wait a bit", 20);
}
[Test]
public void TestTimeDoesNotProgressWhileAllPlayersPaused()
{
start(new[] { PLAYER_1_ID, PLAYER_2_ID });
loadSpectateScreen();
sendFrames(PLAYER_1_ID, 20);
sendFrames(PLAYER_2_ID, 10);
checkPaused(PLAYER_2_ID, true);
checkPausedInstant(PLAYER_1_ID, false);
AddAssert("master clock still running", () => this.ChildrenOfType<MasterGameplayClockContainer>().Single().IsRunning);
checkPaused(PLAYER_1_ID, true);
AddUntilStep("master clock paused", () => !this.ChildrenOfType<MasterGameplayClockContainer>().Single().IsRunning);
}
[Test]
public void TestPlayersMustStartSimultaneously()
{

View File

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Timing;
@ -29,18 +30,22 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// </summary>
public const double MAXIMUM_START_DELAY = 15000;
public event Action ReadyToStart;
/// <summary>
/// The master clock which is used to control the timing of all player clocks clocks.
/// </summary>
public IAdjustableClock MasterClock { get; }
public event Action ReadyToStart;
public IBindable<MasterClockState> MasterState => masterState;
/// <summary>
/// The player clocks.
/// </summary>
private readonly List<ISpectatorPlayerClock> playerClocks = new List<ISpectatorPlayerClock>();
private readonly Bindable<MasterClockState> masterState = new Bindable<MasterClockState>();
private bool hasStarted;
private double? firstStartAttemptTime;
@ -65,7 +70,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
return;
}
updateCatchup();
updatePlayerCatchup();
updateMasterState();
}
/// <summary>
@ -105,7 +111,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// <summary>
/// Updates the catchup states of all player clocks clocks.
/// </summary>
private void updateCatchup()
private void updatePlayerCatchup()
{
for (int i = 0; i < playerClocks.Count; i++)
{
@ -141,5 +147,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
}
}
}
/// <summary>
/// Updates the state of the master clock.
/// </summary>
private void updateMasterState()
{
bool anyInSync = playerClocks.Any(s => !s.IsCatchingUp);
masterState.Value = anyInSync ? MasterClockState.Synchronised : MasterClockState.TooFarAhead;
}
}
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Bindables;
using osu.Framework.Timing;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
@ -11,15 +12,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// </summary>
public interface ISyncManager
{
/// <summary>
/// An event which is invoked when gameplay is ready to start.
/// </summary>
event Action ReadyToStart;
/// <summary>
/// The master clock which player clocks should synchronise to.
/// </summary>
IAdjustableClock MasterClock { get; }
/// <summary>
/// An event which is invoked when gameplay is ready to start.
/// An event which is invoked when the state of <see cref="MasterClock"/> is changed.
/// </summary>
event Action ReadyToStart;
IBindable<MasterClockState> MasterState { get; }
/// <summary>
/// Adds an <see cref="ISpectatorPlayerClock"/> to manage.

View File

@ -0,0 +1,18 @@
// 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.
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
{
public enum MasterClockState
{
/// <summary>
/// The master clock is synchronised with at least one player clock.
/// </summary>
Synchronised,
/// <summary>
/// The master clock is too far ahead of any player clock and needs to slow down.
/// </summary>
TooFarAhead
}
}

View File

@ -5,6 +5,7 @@ using System;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Online.Multiplayer;
@ -103,6 +104,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
}, leaderboardContainer.Add);
syncManager.ReadyToStart += onReadyToStart;
syncManager.MasterState.BindValueChanged(onMasterStateChanged, true);
}
protected override void LoadComplete()
@ -145,6 +147,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
masterClockContainer.Start();
}
private void onMasterStateChanged(ValueChangedEvent<MasterClockState> state)
{
if (state.NewValue == MasterClockState.Synchronised)
masterClockContainer.Start();
else
masterClockContainer.Stop();
}
protected override void OnUserStateChanged(int userId, SpectatorState spectatorState)
{
}