mirror of
https://github.com/ppy/osu.git
synced 2025-01-17 05:43:20 +08:00
Merge branch 'spectator-replay-watcher' into spectator-listing
This commit is contained in:
commit
0818835b16
@ -61,13 +61,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private OsuFramedReplayInputHandler replayHandler =>
|
|
||||||
(OsuFramedReplayInputHandler)Stack.ChildrenOfType<OsuInputManager>().First().ReplayInputHandler;
|
|
||||||
|
|
||||||
private Player player => Stack.CurrentScreen as Player;
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBasicSpectatingFlow()
|
public void TestFrameStarvationAndResume()
|
||||||
{
|
{
|
||||||
loadSpectatingScreen();
|
loadSpectatingScreen();
|
||||||
|
|
||||||
@ -82,11 +77,16 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddUntilStep("wait for frame starvation", () => replayHandler.NextFrame == null);
|
AddUntilStep("wait for frame starvation", () => replayHandler.NextFrame == null);
|
||||||
checkPaused(true);
|
checkPaused(true);
|
||||||
|
|
||||||
|
double? pausedTime = null;
|
||||||
|
|
||||||
|
AddStep("store time", () => pausedTime = currentFrameStableTime);
|
||||||
|
|
||||||
sendFrames();
|
sendFrames();
|
||||||
|
|
||||||
checkPaused(false);
|
|
||||||
AddUntilStep("wait for frame starvation", () => replayHandler.NextFrame == null);
|
AddUntilStep("wait for frame starvation", () => replayHandler.NextFrame == null);
|
||||||
checkPaused(true);
|
checkPaused(true);
|
||||||
|
|
||||||
|
AddAssert("time advanced", () => currentFrameStableTime > pausedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -98,7 +98,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
waitForPlayer();
|
waitForPlayer();
|
||||||
checkPaused(true);
|
checkPaused(true);
|
||||||
|
|
||||||
sendFrames();
|
sendFrames(1000); // send enough frames to ensure play won't be paused
|
||||||
|
|
||||||
checkPaused(false);
|
checkPaused(false);
|
||||||
}
|
}
|
||||||
@ -119,15 +119,23 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHostStartsPlayingWhileAlreadyWatching()
|
public void TestHostRetriesWhileWatching()
|
||||||
{
|
{
|
||||||
loadSpectatingScreen();
|
loadSpectatingScreen();
|
||||||
|
|
||||||
start();
|
start();
|
||||||
sendFrames();
|
sendFrames();
|
||||||
|
|
||||||
|
waitForPlayer();
|
||||||
|
|
||||||
|
Player lastPlayer = null;
|
||||||
|
AddStep("store first player", () => lastPlayer = player);
|
||||||
|
|
||||||
start();
|
start();
|
||||||
sendFrames();
|
sendFrames();
|
||||||
|
|
||||||
|
waitForPlayer();
|
||||||
|
AddAssert("player is different", () => lastPlayer != player);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -155,9 +163,25 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
sendFrames();
|
sendFrames();
|
||||||
waitForPlayer();
|
waitForPlayer();
|
||||||
|
|
||||||
// should immediately exit and unbind from streaming client
|
|
||||||
AddStep("stop spectating", () => (Stack.CurrentScreen as Player)?.Exit());
|
AddStep("stop spectating", () => (Stack.CurrentScreen as Player)?.Exit());
|
||||||
AddUntilStep("spectating stopped", () => spectatorScreen.GetParentScreen() == null);
|
AddUntilStep("spectating stopped", () => spectatorScreen.GetChildScreen() == null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestStopWatchingThenHostRetries()
|
||||||
|
{
|
||||||
|
loadSpectatingScreen();
|
||||||
|
|
||||||
|
start();
|
||||||
|
sendFrames();
|
||||||
|
waitForPlayer();
|
||||||
|
|
||||||
|
AddStep("stop spectating", () => (Stack.CurrentScreen as Player)?.Exit());
|
||||||
|
AddUntilStep("spectating stopped", () => spectatorScreen.GetChildScreen() == null);
|
||||||
|
|
||||||
|
// host starts playing a new session
|
||||||
|
start();
|
||||||
|
waitForPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -171,6 +195,14 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("screen didn't change", () => Stack.CurrentScreen is Spectator);
|
AddAssert("screen didn't change", () => Stack.CurrentScreen is Spectator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private OsuFramedReplayInputHandler replayHandler =>
|
||||||
|
(OsuFramedReplayInputHandler)Stack.ChildrenOfType<OsuInputManager>().First().ReplayInputHandler;
|
||||||
|
|
||||||
|
private Player player => Stack.CurrentScreen as Player;
|
||||||
|
|
||||||
|
private double currentFrameStableTime
|
||||||
|
=> player.ChildrenOfType<FrameStabilityContainer>().First().FrameStableClock.CurrentTime;
|
||||||
|
|
||||||
private void waitForPlayer() => AddUntilStep("wait for player", () => Stack.CurrentScreen is Player);
|
private void waitForPlayer() => AddUntilStep("wait for player", () => Stack.CurrentScreen is Player);
|
||||||
|
|
||||||
private void start(int? beatmapId = null) => AddStep("start play", () => testSpectatorStreamingClient.StartPlay(beatmapId ?? importedBeatmapId));
|
private void start(int? beatmapId = null) => AddStep("start play", () => testSpectatorStreamingClient.StartPlay(beatmapId ?? importedBeatmapId));
|
||||||
|
@ -85,20 +85,31 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
public override bool UpdateSubTree()
|
public override bool UpdateSubTree()
|
||||||
{
|
{
|
||||||
state = frameStableClock.IsPaused.Value ? PlaybackState.NotValid : PlaybackState.Valid;
|
double proposedTime = manualClock.CurrentTime;
|
||||||
|
|
||||||
if (frameStableClock.WaitingOnFrames.Value)
|
if (frameStableClock.WaitingOnFrames.Value)
|
||||||
{
|
{
|
||||||
// for now, force one update loop to check if frames have arrived
|
// when waiting on frames, the update loop still needs to be run (at least once) to check for newly arrived frames.
|
||||||
// this may have to change in the future where we want stable user pausing during replay playback.
|
// time should not be sourced from the parent clock in this case.
|
||||||
state = PlaybackState.Valid;
|
state = PlaybackState.Valid;
|
||||||
}
|
}
|
||||||
|
else if (!frameStableClock.IsPaused.Value)
|
||||||
|
{
|
||||||
|
state = PlaybackState.Valid;
|
||||||
|
proposedTime = parentGameplayClock.CurrentTime;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// time should not advance while paused, not should anything run.
|
||||||
|
state = PlaybackState.NotValid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int loops = MaxCatchUpFrames;
|
int loops = MaxCatchUpFrames;
|
||||||
|
|
||||||
while (state != PlaybackState.NotValid && loops-- > 0)
|
while (loops-- > 0)
|
||||||
{
|
{
|
||||||
updateClock();
|
updateClock(ref proposedTime);
|
||||||
|
|
||||||
if (state == PlaybackState.NotValid)
|
if (state == PlaybackState.NotValid)
|
||||||
break;
|
break;
|
||||||
@ -110,7 +121,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateClock()
|
private void updateClock(ref double proposedTime)
|
||||||
{
|
{
|
||||||
if (parentGameplayClock == null)
|
if (parentGameplayClock == null)
|
||||||
setClock(); // LoadComplete may not be run yet, but we still want the clock.
|
setClock(); // LoadComplete may not be run yet, but we still want the clock.
|
||||||
@ -118,9 +129,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
// each update start with considering things in valid state.
|
// each update start with considering things in valid state.
|
||||||
state = PlaybackState.Valid;
|
state = PlaybackState.Valid;
|
||||||
|
|
||||||
// our goal is to catch up to the time provided by the parent clock.
|
|
||||||
var proposedTime = parentGameplayClock.CurrentTime;
|
|
||||||
|
|
||||||
if (FrameStablePlayback)
|
if (FrameStablePlayback)
|
||||||
// if we require frame stability, the proposed time will be adjusted to move at most one known
|
// if we require frame stability, the proposed time will be adjusted to move at most one known
|
||||||
// frame interval in the current direction.
|
// frame interval in the current direction.
|
||||||
|
Loading…
Reference in New Issue
Block a user