From ec31f37ff7a1c436c054b6e963c0d4f2fa71b9a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 14:50:10 +0900 Subject: [PATCH 01/10] Accept `MasterGameplayClockContainer` rather than generic clock --- .../Spectate/CatchUpSpectatorPlayerClock.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index 8d8f6a373a..c0263d6d0f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Bindables; using osu.Framework.Timing; +using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { @@ -17,15 +18,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double CATCHUP_RATE = 2; - public readonly IFrameBasedClock Source; + private readonly GameplayClockContainer masterClock; public double CurrentTime { get; private set; } public bool IsRunning { get; private set; } - public CatchUpSpectatorPlayerClock(IFrameBasedClock source) + public CatchUpSpectatorPlayerClock(GameplayClockContainer masterClock) { - Source = source; + this.masterClock = masterClock; } public void Reset() => CurrentTime = 0; @@ -69,16 +70,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ElapsedFrameTime = 0; FramesPerSecond = 0; - Source.ProcessFrame(); + masterClock.ProcessFrame(); if (IsRunning) { - double elapsedSource = Source.ElapsedFrameTime; + double elapsedSource = masterClock.ElapsedFrameTime; double elapsed = elapsedSource * Rate; CurrentTime += elapsed; ElapsedFrameTime = elapsed; - FramesPerSecond = Source.FramesPerSecond; + FramesPerSecond = masterClock.FramesPerSecond; } } From 22963ab95162fc13770b128c09e7b8c57b061a87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 13:11:53 +0900 Subject: [PATCH 02/10] Fix multiplayer spectator getting stuck --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 3d04ae8f3c..0f0f29e02e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Online.Multiplayer; @@ -198,6 +199,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void onMasterStateChanged(ValueChangedEvent state) { + Logger.Log($"{nameof(MultiSpectatorScreen)}'s master clock become {state.NewValue}"); + switch (state.NewValue) { case MasterClockState.Synchronised: From 882dd93942356d2122f4c34fe7d41a97bb98c33e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:01:57 +0900 Subject: [PATCH 03/10] Remove `ISyncManager` interface Too many levels of redirection. One interface with one implementation is not useful, IMO. --- .../Spectate/CatchUpSyncManager.cs | 18 +++++++- .../Spectate/ISpectatorPlayerClock.cs | 2 +- .../Multiplayer/Spectate/ISyncManager.cs | 42 ------------------- .../Spectate/MultiSpectatorScreen.cs | 2 +- 4 files changed, 18 insertions(+), 46 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index 4e563ec69a..b9898ad456 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -11,9 +11,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A which synchronises de-synced player clocks through catchup. + /// Manages the synchronisation between one or more s in relation to a master clock. /// - public class CatchUpSyncManager : Component, ISyncManager + public class CatchUpSyncManager : Component { /// /// The offset from the master clock to which player clocks should remain within to be considered in-sync. @@ -30,6 +30,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public const double MAXIMUM_START_DELAY = 15000; + /// + /// An event which is invoked when gameplay is ready to start. + /// public event Action? ReadyToStart; /// @@ -37,6 +40,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public GameplayClockContainer MasterClock { get; } + /// + /// The catch-up state of the master clock. + /// public IBindable MasterState => masterState; /// @@ -54,6 +60,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate MasterClock = master; } + /// + /// Create a new managed . + /// + /// The newly created . public ISpectatorPlayerClock CreateManagedClock() { var clock = new CatchUpSpectatorPlayerClock(MasterClock); @@ -61,6 +71,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate return clock; } + /// + /// Removes an , stopping it from being managed by this . + /// + /// The to remove. public void RemoveManagedClock(ISpectatorPlayerClock clock) { playerClocks.Remove(clock); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs index a2e6df9282..22f835f79e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs @@ -7,7 +7,7 @@ using osu.Framework.Timing; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A clock which is used by s and managed by an . + /// A clock which is used by s and managed by an . /// public interface ISpectatorPlayerClock : IFrameBasedClock, IAdjustableClock { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs deleted file mode 100644 index 5615e02336..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISyncManager.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Bindables; -using osu.Game.Screens.Play; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate -{ - /// - /// Manages the synchronisation between one or more s in relation to a master clock. - /// - public interface ISyncManager - { - /// - /// An event which is invoked when gameplay is ready to start. - /// - event Action? ReadyToStart; - - /// - /// The master clock which player clocks should synchronise to. - /// - GameplayClockContainer MasterClock { get; } - - /// - /// An event which is invoked when the state of is changed. - /// - IBindable MasterState { get; } - - /// - /// Create a new managed . - /// - /// The newly created . - ISpectatorPlayerClock CreateManagedClock(); - - /// - /// Removes an , stopping it from being managed by this . - /// - /// The to remove. - void RemoveManagedClock(ISpectatorPlayerClock clock); - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 0f0f29e02e..0177003bb2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly PlayerArea[] instances; private MasterGameplayClockContainer masterClockContainer = null!; - private ISyncManager syncManager = null!; + private CatchUpSyncManager syncManager = null!; private PlayerGrid grid = null!; private MultiSpectatorLeaderboard leaderboard = null!; private PlayerArea? currentAudioSource; From 31f657fe01f7b7ce53b7ef3fa07fed91bb4502ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:04:52 +0900 Subject: [PATCH 04/10] Remove `ISpectatorPlayerClock` interface Too many levels of redirection. One interface with one implementation is not useful, IMO. --- .../OnlinePlay/TestSceneCatchUpSyncManager.cs | 16 ++++---- .../Spectate/CatchUpSpectatorPlayerClock.cs | 19 +++++++++- .../Spectate/CatchUpSyncManager.cs | 16 ++++---- .../Spectate/ISpectatorPlayerClock.cs | 37 ------------------- .../Spectate/MultiSpectatorPlayer.cs | 4 +- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Multiplayer/Spectate/PlayerArea.cs | 6 +-- 7 files changed, 39 insertions(+), 61 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index db14dc95b2..263ce7c9bd 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -21,9 +21,9 @@ namespace osu.Game.Tests.OnlinePlay private GameplayClockContainer master; private CatchUpSyncManager syncManager; - private Dictionary clocksById; - private ISpectatorPlayerClock player1; - private ISpectatorPlayerClock player2; + private Dictionary clocksById; + private CatchUpSpectatorPlayerClock player1; + private CatchUpSpectatorPlayerClock player2; [SetUp] public void Setup() @@ -32,7 +32,7 @@ namespace osu.Game.Tests.OnlinePlay player1 = syncManager.CreateManagedClock(); player2 = syncManager.CreateManagedClock(); - clocksById = new Dictionary + clocksById = new Dictionary { { player1, 1 }, { player2, 2 } @@ -145,7 +145,7 @@ namespace osu.Game.Tests.OnlinePlay assertPlayerClockState(() => player1, false); } - private void setWaiting(Func playerClock, bool waiting) + private void setWaiting(Func playerClock, bool waiting) => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () => @@ -160,13 +160,13 @@ namespace osu.Game.Tests.OnlinePlay /// /// clock.Time = master.Time - offsetFromMaster /// - private void setPlayerClockTime(Func playerClock, double offsetFromMaster) + private void setPlayerClockTime(Func playerClock, double offsetFromMaster) => AddStep($"set player clock {clocksById[playerClock()]} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster)); - private void assertCatchingUp(Func playerClock, bool catchingUp) => + private void assertCatchingUp(Func playerClock, bool catchingUp) => AddAssert($"player clock {clocksById[playerClock()]} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp); - private void assertPlayerClockState(Func playerClock, bool running) + private void assertPlayerClockState(Func playerClock, bool running) => AddAssert($"player clock {clocksById[playerClock()]} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running); private class TestManualClock : ManualClock, IAdjustableClock diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs index c0263d6d0f..15821fb133 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs @@ -9,9 +9,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A which catches up using rate adjustment. + /// A which catches up using rate adjustment. /// - public class CatchUpSpectatorPlayerClock : ISpectatorPlayerClock + public class CatchUpSpectatorPlayerClock : IFrameBasedClock, IAdjustableClock { /// /// The catch up rate. @@ -31,8 +31,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void Reset() => CurrentTime = 0; + /// + /// Starts this . + /// public void Start() => IsRunning = true; + /// + /// Stops this . + /// public void Stop() => IsRunning = false; void IAdjustableClock.Start() @@ -89,8 +95,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public FrameTimeInfo TimeInfo => new FrameTimeInfo { Elapsed = ElapsedFrameTime, Current = CurrentTime }; + /// + /// Whether this clock is waiting on frames to continue playback. + /// public Bindable WaitingOnFrames { get; } = new Bindable(true); + /// + /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. + /// + /// + /// Of note, this will be false if this clock is *ahead* of the master clock. + /// public bool IsCatchingUp { get; set; } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index b9898ad456..71fbb8cbee 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -11,7 +11,7 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// Manages the synchronisation between one or more s in relation to a master clock. + /// Manages the synchronisation between one or more s in relation to a master clock. /// public class CatchUpSyncManager : Component { @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The player clocks. /// - private readonly List playerClocks = new List(); + private readonly List playerClocks = new List(); private readonly Bindable masterState = new Bindable(); @@ -61,10 +61,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } /// - /// Create a new managed . + /// Create a new managed . /// - /// The newly created . - public ISpectatorPlayerClock CreateManagedClock() + /// The newly created . + public CatchUpSpectatorPlayerClock CreateManagedClock() { var clock = new CatchUpSpectatorPlayerClock(MasterClock); playerClocks.Add(clock); @@ -72,10 +72,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } /// - /// Removes an , stopping it from being managed by this . + /// Removes an , stopping it from being managed by this . /// - /// The to remove. - public void RemoveManagedClock(ISpectatorPlayerClock clock) + /// The to remove. + public void RemoveManagedClock(CatchUpSpectatorPlayerClock clock) { playerClocks.Remove(clock); clock.Stop(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs deleted file mode 100644 index 22f835f79e..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/ISpectatorPlayerClock.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Framework.Timing; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate -{ - /// - /// A clock which is used by s and managed by an . - /// - public interface ISpectatorPlayerClock : IFrameBasedClock, IAdjustableClock - { - /// - /// Starts this . - /// - new void Start(); - - /// - /// Stops this . - /// - new void Stop(); - - /// - /// Whether this clock is waiting on frames to continue playback. - /// - Bindable WaitingOnFrames { get; } - - /// - /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. - /// - /// - /// Of note, this will be false if this clock is *ahead* of the master clock. - /// - bool IsCatchingUp { get; set; } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 68eae76030..4821eb69c6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -15,14 +15,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public class MultiSpectatorPlayer : SpectatorPlayer { private readonly Bindable waitingOnFrames = new Bindable(true); - private readonly ISpectatorPlayerClock spectatorPlayerClock; + private readonly CatchUpSpectatorPlayerClock spectatorPlayerClock; /// /// Creates a new . /// /// The score containing the player's replay. /// The clock controlling the gameplay running state. - public MultiSpectatorPlayer(Score score, ISpectatorPlayerClock spectatorPlayerClock) + public MultiSpectatorPlayer(Score score, CatchUpSpectatorPlayerClock spectatorPlayerClock) : base(score, new PlayerConfiguration { AllowUserInteraction = false }) { this.spectatorPlayerClock = spectatorPlayerClock; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 0177003bb2..ac66aa160c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -177,7 +177,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } } - private bool isCandidateAudioSource(ISpectatorPlayerClock? clock) + private bool isCandidateAudioSource(CatchUpSpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames.Value; private void onReadyToStart() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 7e679383c4..451f4e0b79 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -38,9 +38,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public readonly int UserId; /// - /// The used to control the gameplay running state of a loaded . + /// The used to control the gameplay running state of a loaded . /// - public readonly ISpectatorPlayerClock GameplayClock; + public readonly CatchUpSpectatorPlayerClock GameplayClock; /// /// The currently-loaded score. @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly LoadingLayer loadingLayer; private OsuScreenStack? stack; - public PlayerArea(int userId, ISpectatorPlayerClock clock) + public PlayerArea(int userId, CatchUpSpectatorPlayerClock clock) { UserId = userId; GameplayClock = clock; From 995e6664b612aac7d2c8565b8ab1a839c227bab8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:07:04 +0900 Subject: [PATCH 05/10] Rename spectator clock sync classes --- .../OnlinePlay/TestSceneCatchUpSyncManager.cs | 38 +++++++++---------- .../TestSceneMultiSpectatorScreen.cs | 4 +- .../Spectate/MultiSpectatorPlayer.cs | 8 ++-- .../Spectate/MultiSpectatorScreen.cs | 6 +-- .../Multiplayer/Spectate/PlayerArea.cs | 6 +-- ...PlayerClock.cs => SpectatorPlayerClock.cs} | 10 ++--- ...SyncManager.cs => SpectatorSyncManager.cs} | 22 +++++------ 7 files changed, 47 insertions(+), 47 deletions(-) rename osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/{CatchUpSpectatorPlayerClock.cs => SpectatorPlayerClock.cs} (88%) rename osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/{CatchUpSyncManager.cs => SpectatorSyncManager.cs} (86%) diff --git a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs index 263ce7c9bd..5761a89ae8 100644 --- a/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs +++ b/osu.Game.Tests/OnlinePlay/TestSceneCatchUpSyncManager.cs @@ -19,20 +19,20 @@ namespace osu.Game.Tests.OnlinePlay public class TestSceneCatchUpSyncManager : OsuTestScene { private GameplayClockContainer master; - private CatchUpSyncManager syncManager; + private SpectatorSyncManager syncManager; - private Dictionary clocksById; - private CatchUpSpectatorPlayerClock player1; - private CatchUpSpectatorPlayerClock player2; + private Dictionary clocksById; + private SpectatorPlayerClock player1; + private SpectatorPlayerClock player2; [SetUp] public void Setup() { - syncManager = new CatchUpSyncManager(master = new GameplayClockContainer(new TestManualClock())); + syncManager = new SpectatorSyncManager(master = new GameplayClockContainer(new TestManualClock())); player1 = syncManager.CreateManagedClock(); player2 = syncManager.CreateManagedClock(); - clocksById = new Dictionary + clocksById = new Dictionary { { player1, 1 }, { player2, 2 } @@ -64,7 +64,7 @@ namespace osu.Game.Tests.OnlinePlay public void TestReadyPlayersStartWhenReadyForMaximumDelayTime() { setWaiting(() => player1, false); - AddWaitStep($"wait {CatchUpSyncManager.MAXIMUM_START_DELAY} milliseconds", (int)Math.Ceiling(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction)); + AddWaitStep($"wait {SpectatorSyncManager.MAXIMUM_START_DELAY} milliseconds", (int)Math.Ceiling(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); assertPlayerClockState(() => player1, true); assertPlayerClockState(() => player2, false); } @@ -74,7 +74,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.SYNC_TARGET + 1); + setMasterTime(SpectatorSyncManager.SYNC_TARGET + 1); assertCatchingUp(() => player1, false); } @@ -83,7 +83,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 1); + setMasterTime(SpectatorSyncManager.MAX_SYNC_OFFSET + 1); assertCatchingUp(() => player1, true); assertCatchingUp(() => player2, true); } @@ -93,8 +93,8 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 1); - setPlayerClockTime(() => player1, CatchUpSyncManager.SYNC_TARGET + 1); + setMasterTime(SpectatorSyncManager.MAX_SYNC_OFFSET + 1); + setPlayerClockTime(() => player1, SpectatorSyncManager.SYNC_TARGET + 1); assertCatchingUp(() => player1, true); } @@ -103,8 +103,8 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setMasterTime(CatchUpSyncManager.MAX_SYNC_OFFSET + 2); - setPlayerClockTime(() => player1, CatchUpSyncManager.SYNC_TARGET); + setMasterTime(SpectatorSyncManager.MAX_SYNC_OFFSET + 2); + setPlayerClockTime(() => player1, SpectatorSyncManager.SYNC_TARGET); assertCatchingUp(() => player1, false); assertCatchingUp(() => player2, true); } @@ -114,7 +114,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setPlayerClockTime(() => player1, -CatchUpSyncManager.SYNC_TARGET); + setPlayerClockTime(() => player1, -SpectatorSyncManager.SYNC_TARGET); assertCatchingUp(() => player1, false); assertPlayerClockState(() => player1, true); } @@ -124,7 +124,7 @@ namespace osu.Game.Tests.OnlinePlay { setAllWaiting(false); - setPlayerClockTime(() => player1, -CatchUpSyncManager.SYNC_TARGET - 1); + setPlayerClockTime(() => player1, -SpectatorSyncManager.SYNC_TARGET - 1); // This is a silent catchup, where IsCatchingUp = false but IsRunning = false also. assertCatchingUp(() => player1, false); @@ -145,7 +145,7 @@ namespace osu.Game.Tests.OnlinePlay assertPlayerClockState(() => player1, false); } - private void setWaiting(Func playerClock, bool waiting) + private void setWaiting(Func playerClock, bool waiting) => AddStep($"set player clock {clocksById[playerClock()]} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting); private void setAllWaiting(bool waiting) => AddStep($"set all player clocks waiting = {waiting}", () => @@ -160,13 +160,13 @@ namespace osu.Game.Tests.OnlinePlay /// /// clock.Time = master.Time - offsetFromMaster /// - private void setPlayerClockTime(Func playerClock, double offsetFromMaster) + private void setPlayerClockTime(Func playerClock, double offsetFromMaster) => AddStep($"set player clock {clocksById[playerClock()]} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster)); - private void assertCatchingUp(Func playerClock, bool catchingUp) => + private void assertCatchingUp(Func playerClock, bool catchingUp) => AddAssert($"player clock {clocksById[playerClock()]} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp); - private void assertPlayerClockState(Func playerClock, bool running) + private void assertPlayerClockState(Func playerClock, bool running) => AddAssert($"player clock {clocksById[playerClock()]} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running); private class TestManualClock : ManualClock, IAdjustableClock diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index a2e3ab7318..bab613bed7 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -202,7 +202,7 @@ namespace osu.Game.Tests.Visual.Multiplayer checkPausedInstant(PLAYER_2_ID, true); // Wait for the start delay seconds... - AddWaitStep("wait maximum start delay seconds", (int)(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction)); + AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); // Player 1 should start playing by itself, player 2 should remain paused. checkPausedInstant(PLAYER_1_ID, false); @@ -318,7 +318,7 @@ namespace osu.Game.Tests.Visual.Multiplayer loadSpectateScreen(); sendFrames(PLAYER_1_ID, 300); - AddWaitStep("wait maximum start delay seconds", (int)(CatchUpSyncManager.MAXIMUM_START_DELAY / TimePerAction)); + AddWaitStep("wait maximum start delay seconds", (int)(SpectatorSyncManager.MAXIMUM_START_DELAY / TimePerAction)); checkPaused(PLAYER_1_ID, false); sendFrames(PLAYER_2_ID, 300); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 4821eb69c6..8445a6fdf0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -15,14 +15,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public class MultiSpectatorPlayer : SpectatorPlayer { private readonly Bindable waitingOnFrames = new Bindable(true); - private readonly CatchUpSpectatorPlayerClock spectatorPlayerClock; + private readonly SpectatorPlayerClock spectatorPlayerClock; /// /// Creates a new . /// /// The score containing the player's replay. /// The clock controlling the gameplay running state. - public MultiSpectatorPlayer(Score score, CatchUpSpectatorPlayerClock spectatorPlayerClock) + public MultiSpectatorPlayer(Score score, SpectatorPlayerClock spectatorPlayerClock) : base(score, new PlayerConfiguration { AllowUserInteraction = false }) { this.spectatorPlayerClock = spectatorPlayerClock; @@ -40,9 +40,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override void Update() { // The player clock's running state is controlled externally, but the local pausing state needs to be updated to start/stop gameplay. - CatchUpSpectatorPlayerClock catchUpClock = (CatchUpSpectatorPlayerClock)GameplayClockContainer.SourceClock; + SpectatorPlayerClock clock = (SpectatorPlayerClock)GameplayClockContainer.SourceClock; - if (catchUpClock.IsRunning) + if (clock.IsRunning) GameplayClockContainer.Start(); else GameplayClockContainer.Stop(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index ac66aa160c..8af5a640fa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -48,7 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly PlayerArea[] instances; private MasterGameplayClockContainer masterClockContainer = null!; - private CatchUpSyncManager syncManager = null!; + private SpectatorSyncManager syncManager = null!; private PlayerGrid grid = null!; private MultiSpectatorLeaderboard leaderboard = null!; private PlayerArea? currentAudioSource; @@ -81,7 +81,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate InternalChildren = new[] { - (Drawable)(syncManager = new CatchUpSyncManager(masterClockContainer)), + (Drawable)(syncManager = new SpectatorSyncManager(masterClockContainer)), masterClockContainer.WithChild(new GridContainer { RelativeSizeAxes = Axes.Both, @@ -177,7 +177,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate } } - private bool isCandidateAudioSource(CatchUpSpectatorPlayerClock? clock) + private bool isCandidateAudioSource(SpectatorPlayerClock? clock) => clock?.IsRunning == true && !clock.IsCatchingUp && !clock.WaitingOnFrames.Value; private void onReadyToStart() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs index 451f4e0b79..a1fbdc10de 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/PlayerArea.cs @@ -38,9 +38,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public readonly int UserId; /// - /// The used to control the gameplay running state of a loaded . + /// The used to control the gameplay running state of a loaded . /// - public readonly CatchUpSpectatorPlayerClock GameplayClock; + public readonly SpectatorPlayerClock GameplayClock; /// /// The currently-loaded score. @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private readonly LoadingLayer loadingLayer; private OsuScreenStack? stack; - public PlayerArea(int userId, CatchUpSpectatorPlayerClock clock) + public PlayerArea(int userId, SpectatorPlayerClock clock) { UserId = userId; GameplayClock = clock; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs similarity index 88% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 15821fb133..729a120dc1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -9,9 +9,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// A which catches up using rate adjustment. + /// A clock which catches up using rate adjustment. /// - public class CatchUpSpectatorPlayerClock : IFrameBasedClock, IAdjustableClock + public class SpectatorPlayerClock : IFrameBasedClock, IAdjustableClock { /// /// The catch up rate. @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public bool IsRunning { get; private set; } - public CatchUpSpectatorPlayerClock(GameplayClockContainer masterClock) + public SpectatorPlayerClock(GameplayClockContainer masterClock) { this.masterClock = masterClock; } @@ -32,12 +32,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void Reset() => CurrentTime = 0; /// - /// Starts this . + /// Starts this . /// public void Start() => IsRunning = true; /// - /// Stops this . + /// Stops this . /// public void Stop() => IsRunning = false; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs similarity index 86% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs rename to osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 71fbb8cbee..d2f2efffc9 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -11,9 +11,9 @@ using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { /// - /// Manages the synchronisation between one or more s in relation to a master clock. + /// Manages the synchronisation between one or more s in relation to a master clock. /// - public class CatchUpSyncManager : Component + public class SpectatorSyncManager : Component { /// /// The offset from the master clock to which player clocks should remain within to be considered in-sync. @@ -48,34 +48,34 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The player clocks. /// - private readonly List playerClocks = new List(); + private readonly List playerClocks = new List(); private readonly Bindable masterState = new Bindable(); private bool hasStarted; private double? firstStartAttemptTime; - public CatchUpSyncManager(GameplayClockContainer master) + public SpectatorSyncManager(GameplayClockContainer master) { MasterClock = master; } /// - /// Create a new managed . + /// Create a new managed . /// - /// The newly created . - public CatchUpSpectatorPlayerClock CreateManagedClock() + /// The newly created . + public SpectatorPlayerClock CreateManagedClock() { - var clock = new CatchUpSpectatorPlayerClock(MasterClock); + var clock = new SpectatorPlayerClock(MasterClock); playerClocks.Add(clock); return clock; } /// - /// Removes an , stopping it from being managed by this . + /// Removes an , stopping it from being managed by this . /// - /// The to remove. - public void RemoveManagedClock(CatchUpSpectatorPlayerClock clock) + /// The to remove. + public void RemoveManagedClock(SpectatorPlayerClock clock) { playerClocks.Remove(clock); clock.Stop(); From 0c9a4ec13cab46f49bd04da9b03897a3c523cc16 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:09:00 +0900 Subject: [PATCH 06/10] Don't expose `MasterClock` in `SpectatorClockSyncManager` --- .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Spectate/SpectatorSyncManager.cs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 8af5a640fa..b285d3d7c2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate if (!isCandidateAudioSource(currentAudioSource?.GameplayClock)) { currentAudioSource = instances.Where(i => isCandidateAudioSource(i.GameplayClock)) - .OrderBy(i => Math.Abs(i.GameplayClock.CurrentTime - syncManager.MasterClock.CurrentTime)) + .OrderBy(i => Math.Abs(i.GameplayClock.CurrentTime - syncManager.CurrentMasterTime)) .FirstOrDefault(); foreach (var instance in instances) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index d2f2efffc9..aa6fb878b3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -35,16 +35,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public event Action? ReadyToStart; - /// - /// The master clock which is used to control the timing of all player clocks clocks. - /// - public GameplayClockContainer MasterClock { get; } - /// /// The catch-up state of the master clock. /// public IBindable MasterState => masterState; + public double CurrentMasterTime => masterClock.CurrentTime; + + /// + /// The master clock which is used to control the timing of all player clocks clocks. + /// + private GameplayClockContainer masterClock { get; } + /// /// The player clocks. /// @@ -57,7 +59,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public SpectatorSyncManager(GameplayClockContainer master) { - MasterClock = master; + masterClock = master; } /// @@ -66,7 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// The newly created . public SpectatorPlayerClock CreateManagedClock() { - var clock = new SpectatorPlayerClock(MasterClock); + var clock = new SpectatorPlayerClock(masterClock); playerClocks.Add(clock); return clock; } @@ -142,7 +144,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate // How far this player's clock is out of sync, compared to the master clock. // A negative value means the player is running fast (ahead); a positive value means the player is running behind (catching up). - double timeDelta = MasterClock.CurrentTime - clock.CurrentTime; + double timeDelta = masterClock.CurrentTime - clock.CurrentTime; // Check that the player clock isn't too far ahead. // This is a quiet case in which the catchup is done by the master clock, so IsCatchingUp is not set on the player clock. From a86fc6f248b3c4712a9542409de54c8608d973a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:17:56 +0900 Subject: [PATCH 07/10] Change running state of `SpectatorPlayerClock` using `IsRunning` --- .../Spectate/SpectatorPlayerClock.cs | 50 ++++++++----------- .../Spectate/SpectatorSyncManager.cs | 11 ++-- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs index 729a120dc1..4e785ad3b1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorPlayerClock.cs @@ -22,7 +22,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public double CurrentTime { get; private set; } - public bool IsRunning { get; private set; } + /// + /// Whether this clock is waiting on frames to continue playback. + /// + public Bindable WaitingOnFrames { get; } = new Bindable(true); + + /// + /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. + /// + /// + /// Of note, this will be false if this clock is *ahead* of the master clock. + /// + public bool IsCatchingUp { get; set; } + + /// + /// Whether this spectator clock should be running. + /// Use instead of / to control time. + /// + public bool IsRunning { get; set; } public SpectatorPlayerClock(GameplayClockContainer masterClock) { @@ -31,24 +48,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void Reset() => CurrentTime = 0; - /// - /// Starts this . - /// - public void Start() => IsRunning = true; - - /// - /// Stops this . - /// - public void Stop() => IsRunning = false; - - void IAdjustableClock.Start() + public void Start() { - // Our running state should only be managed by an ISyncManager, ignore calls from external sources. + // Our running state should only be managed by SpectatorSyncManager via IsRunning. } - void IAdjustableClock.Stop() + public void Stop() { - // Our running state should only be managed by an ISyncManager, ignore calls from external sources. + // Our running state should only be managed by an SpectatorSyncManager via IsRunning. } public bool Seek(double position) @@ -94,18 +101,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public double FramesPerSecond { get; private set; } public FrameTimeInfo TimeInfo => new FrameTimeInfo { Elapsed = ElapsedFrameTime, Current = CurrentTime }; - - /// - /// Whether this clock is waiting on frames to continue playback. - /// - public Bindable WaitingOnFrames { get; } = new Bindable(true); - - /// - /// Whether this clock is behind the master clock and running at a higher rate to catch up to it. - /// - /// - /// Of note, this will be false if this clock is *ahead* of the master clock. - /// - public bool IsCatchingUp { get; set; } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index aa6fb878b3..7ec8f45b1f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -80,7 +80,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public void RemoveManagedClock(SpectatorPlayerClock clock) { playerClocks.Remove(clock); - clock.Stop(); + clock.IsRunning = false; } protected override void Update() @@ -91,7 +91,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { // Ensure all player clocks are stopped until the start succeeds. foreach (var clock in playerClocks) - clock.Stop(); + clock.IsRunning = true; return; } @@ -153,15 +153,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate // Importantly, set the clock to a non-catchup state. if this isn't done, updateMasterState may incorrectly pause the master clock // when it is required to be running (ie. if all players are ahead of the master). clock.IsCatchingUp = false; - clock.Stop(); + clock.IsRunning = false; continue; } // Make sure the player clock is running if it can. - if (!clock.WaitingOnFrames.Value) - clock.Start(); - else - clock.Stop(); + clock.IsRunning = !clock.WaitingOnFrames.Value; if (clock.IsCatchingUp) { From b6254a1f252f55750cb66a9033f8e65719b35291 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:23:31 +0900 Subject: [PATCH 08/10] Remove unnecessary casting --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 8445a6fdf0..57af929cb7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -40,9 +40,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override void Update() { // The player clock's running state is controlled externally, but the local pausing state needs to be updated to start/stop gameplay. - SpectatorPlayerClock clock = (SpectatorPlayerClock)GameplayClockContainer.SourceClock; - - if (clock.IsRunning) + if (GameplayClockContainer.SourceClock.IsRunning) GameplayClockContainer.Start(); else GameplayClockContainer.Stop(); From 0b271fe4b3ae9a9e4aa78cb138136a37bcba342c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:27:31 +0900 Subject: [PATCH 09/10] Fix incorrect `IsRunning` value --- .../OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index 7ec8f45b1f..c7b70cc6c7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -91,7 +91,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { // Ensure all player clocks are stopped until the start succeeds. foreach (var clock in playerClocks) - clock.IsRunning = true; + clock.IsRunning = false; return; } From b4eede61fb6c1b2dbfd13e262d9c90c1ac42400f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 24 Aug 2022 15:28:18 +0900 Subject: [PATCH 10/10] Use `readonly` instead of `get-only` --- .../OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs index c7b70cc6c7..119e82a682 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/SpectatorSyncManager.cs @@ -45,7 +45,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// The master clock which is used to control the timing of all player clocks clocks. /// - private GameplayClockContainer masterClock { get; } + private readonly GameplayClockContainer masterClock; /// /// The player clocks.