1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 10:18:22 +08:00

Invert creation of clocks in multi spectator

This commit is contained in:
Dan Balasescu 2022-08-22 19:14:06 +09:00
parent 3fb3a18e68
commit 5d3d8681d4
5 changed files with 50 additions and 76 deletions

View File

@ -4,11 +4,13 @@
#nullable disable
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
namespace osu.Game.Tests.OnlinePlay
@ -16,20 +18,34 @@ namespace osu.Game.Tests.OnlinePlay
[HeadlessTest]
public class TestSceneCatchUpSyncManager : OsuTestScene
{
private TestManualClock master;
private GameplayClockContainer master;
private CatchUpSyncManager syncManager;
private TestSpectatorPlayerClock player1;
private TestSpectatorPlayerClock player2;
private Dictionary<ISpectatorPlayerClock, int> clocksById;
private ISpectatorPlayerClock player1;
private ISpectatorPlayerClock player2;
[SetUp]
public void Setup()
{
syncManager = new CatchUpSyncManager(master = new TestManualClock());
syncManager.AddPlayerClock(player1 = new TestSpectatorPlayerClock(1));
syncManager.AddPlayerClock(player2 = new TestSpectatorPlayerClock(2));
syncManager = new CatchUpSyncManager(master = new GameplayClockContainer(new TestManualClock()));
player1 = syncManager.AddClock();
player2 = syncManager.AddClock();
Schedule(() => Child = syncManager);
clocksById = new Dictionary<ISpectatorPlayerClock, int>
{
{ player1, 1 },
{ player2, 2 }
};
Schedule(() =>
{
Children = new Drawable[]
{
syncManager,
master
};
});
}
[Test]
@ -129,8 +145,8 @@ namespace osu.Game.Tests.OnlinePlay
assertPlayerClockState(() => player1, false);
}
private void setWaiting(Func<TestSpectatorPlayerClock> playerClock, bool waiting)
=> AddStep($"set player clock {playerClock().Id} waiting = {waiting}", () => playerClock().WaitingOnFrames.Value = waiting);
private void setWaiting(Func<ISpectatorPlayerClock> 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}", () =>
{
@ -144,51 +160,14 @@ namespace osu.Game.Tests.OnlinePlay
/// <summary>
/// clock.Time = master.Time - offsetFromMaster
/// </summary>
private void setPlayerClockTime(Func<TestSpectatorPlayerClock> playerClock, double offsetFromMaster)
=> AddStep($"set player clock {playerClock().Id} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster));
private void setPlayerClockTime(Func<ISpectatorPlayerClock> playerClock, double offsetFromMaster)
=> AddStep($"set player clock {clocksById[playerClock()]} = master - {offsetFromMaster}", () => playerClock().Seek(master.CurrentTime - offsetFromMaster));
private void assertCatchingUp(Func<TestSpectatorPlayerClock> playerClock, bool catchingUp) =>
AddAssert($"player clock {playerClock().Id} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp);
private void assertCatchingUp(Func<ISpectatorPlayerClock> playerClock, bool catchingUp) =>
AddAssert($"player clock {clocksById[playerClock()]} {(catchingUp ? "is" : "is not")} catching up", () => playerClock().IsCatchingUp == catchingUp);
private void assertPlayerClockState(Func<TestSpectatorPlayerClock> playerClock, bool running)
=> AddAssert($"player clock {playerClock().Id} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running);
private class TestSpectatorPlayerClock : TestManualClock, ISpectatorPlayerClock
{
public Bindable<bool> WaitingOnFrames { get; } = new Bindable<bool>(true);
public bool IsCatchingUp { get; set; }
public IFrameBasedClock Source
{
set => throw new NotImplementedException();
}
public readonly int Id;
public TestSpectatorPlayerClock(int id)
{
Id = id;
WaitingOnFrames.BindValueChanged(waiting =>
{
if (waiting.NewValue)
Stop();
else
Start();
});
}
public void ProcessFrame()
{
}
public double ElapsedFrameTime => 0;
public double FramesPerSecond => 0;
public FrameTimeInfo TimeInfo => default;
}
private void assertPlayerClockState(Func<ISpectatorPlayerClock> playerClock, bool running)
=> AddAssert($"player clock {clocksById[playerClock()]} {(running ? "is" : "is not")} running", () => playerClock().IsRunning == running);
private class TestManualClock : ManualClock, IAdjustableClock
{

View File

@ -5,11 +5,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Screens.Play;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
{
@ -38,7 +37,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// <summary>
/// The master clock which is used to control the timing of all player clocks clocks.
/// </summary>
public IAdjustableClock MasterClock { get; }
public GameplayClockContainer MasterClock { get; }
public IBindable<MasterClockState> MasterState => masterState;
@ -52,18 +51,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
private bool hasStarted;
private double? firstStartAttemptTime;
public CatchUpSyncManager(IAdjustableClock master)
public CatchUpSyncManager(GameplayClockContainer master)
{
MasterClock = master;
}
public void AddPlayerClock(ISpectatorPlayerClock clock)
public ISpectatorPlayerClock AddClock()
{
Debug.Assert(!playerClocks.Contains(clock));
var clock = new CatchUpSpectatorPlayerClock { Source = MasterClock };
playerClocks.Add(clock);
return clock;
}
public void RemovePlayerClock(ISpectatorPlayerClock clock)
public void RemoveClock(ISpectatorPlayerClock clock)
{
playerClocks.Remove(clock);
clock.Stop();

View File

@ -5,7 +5,7 @@
using System;
using osu.Framework.Bindables;
using osu.Framework.Timing;
using osu.Game.Screens.Play;
namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
{
@ -22,7 +22,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// <summary>
/// The master clock which player clocks should synchronise to.
/// </summary>
IAdjustableClock MasterClock { get; }
GameplayClockContainer MasterClock { get; }
/// <summary>
/// An event which is invoked when the state of <see cref="MasterClock"/> is changed.
@ -30,15 +30,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
IBindable<MasterClockState> MasterState { get; }
/// <summary>
/// Adds an <see cref="ISpectatorPlayerClock"/> to manage.
/// Adds a new managed <see cref="ISpectatorPlayerClock"/>.
/// </summary>
/// <param name="clock">The <see cref="ISpectatorPlayerClock"/> to add.</param>
void AddPlayerClock(ISpectatorPlayerClock clock);
/// <returns>The added <see cref="ISpectatorPlayerClock"/>.</returns>
ISpectatorPlayerClock AddClock();
/// <summary>
/// Removes an <see cref="ISpectatorPlayerClock"/>, stopping it from being managed by this <see cref="ISyncManager"/>.
/// </summary>
/// <param name="clock">The <see cref="ISpectatorPlayerClock"/> to remove.</param>
void RemovePlayerClock(ISpectatorPlayerClock clock);
void RemoveClock(ISpectatorPlayerClock clock);
}
}

View File

@ -125,10 +125,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
};
for (int i = 0; i < Users.Count; i++)
{
grid.Add(instances[i] = new PlayerArea(Users[i], masterClockContainer));
syncManager.AddPlayerClock(instances[i].GameplayClock);
}
grid.Add(instances[i] = new PlayerArea(Users[i], syncManager.AddClock()));
LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(users)
{
@ -242,7 +239,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
var instance = instances.Single(i => i.UserId == userId);
instance.FadeColour(colours.Gray4, 400, Easing.OutQuint);
syncManager.RemovePlayerClock(instance.GameplayClock);
syncManager.RemoveClock(instance.GameplayClock);
}
public override bool OnBackButton()

View File

@ -11,7 +11,6 @@ using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
@ -45,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// The <see cref="ISpectatorPlayerClock"/> used to control the gameplay running state of a loaded <see cref="Player"/>.
/// </summary>
[NotNull]
public readonly ISpectatorPlayerClock GameplayClock = new CatchUpSpectatorPlayerClock();
public readonly ISpectatorPlayerClock GameplayClock;
/// <summary>
/// The currently-loaded score.
@ -58,9 +57,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
private readonly LoadingLayer loadingLayer;
private OsuScreenStack stack;
public PlayerArea(int userId, IFrameBasedClock masterClock)
public PlayerArea(int userId, [NotNull] ISpectatorPlayerClock clock)
{
UserId = userId;
GameplayClock = clock;
RelativeSizeAxes = Axes.Both;
Masking = true;
@ -77,8 +77,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
};
audioContainer.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment);
GameplayClock.Source = masterClock;
}
[Resolved]