1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-27 18:32:56 +08:00

Give SpectatorState a user state

This commit is contained in:
Dan Balasescu 2022-02-01 15:51:41 +09:00
parent 38e075c522
commit 41007169f7
6 changed files with 52 additions and 6 deletions

View File

@ -211,7 +211,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("send frames and finish play", () => AddStep("send frames and finish play", () =>
{ {
spectatorClient.HandleFrame(new OsuReplayFrame(1000, Vector2.Zero)); spectatorClient.HandleFrame(new OsuReplayFrame(1000, Vector2.Zero));
spectatorClient.EndPlaying(); spectatorClient.EndPlaying(new GameplayState(new TestBeatmap(new OsuRuleset().RulesetInfo), new OsuRuleset()) { HasPassed = true });
}); });
// We can't access API because we're an "online" test. // We can't access API because we're an "online" test.

View File

@ -0,0 +1,33 @@
// 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.Online.Spectator
{
public enum SpectatingUserState
{
/// <summary>
/// The spectated user has not yet played.
/// </summary>
Idle,
/// <summary>
/// The spectated user is currently playing.
/// </summary>
Playing,
/// <summary>
/// The spectated user has successfully completed gameplay.
/// </summary>
Completed,
/// <summary>
/// The spectator user has failed during gameplay.
/// </summary>
Failed,
/// <summary>
/// The spectated user has quit during gameplay.
/// </summary>
Quit
}
}

View File

@ -138,6 +138,7 @@ namespace osu.Game.Online.Spectator
currentState.BeatmapID = score.ScoreInfo.BeatmapInfo.OnlineID; currentState.BeatmapID = score.ScoreInfo.BeatmapInfo.OnlineID;
currentState.RulesetID = score.ScoreInfo.RulesetID; currentState.RulesetID = score.ScoreInfo.RulesetID;
currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray(); currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray();
currentState.State = SpectatingUserState.Playing;
currentBeatmap = state.Beatmap; currentBeatmap = state.Beatmap;
currentScore = score; currentScore = score;
@ -148,7 +149,7 @@ namespace osu.Game.Online.Spectator
public void SendFrames(FrameDataBundle data) => lastSend = SendFramesInternal(data); public void SendFrames(FrameDataBundle data) => lastSend = SendFramesInternal(data);
public void EndPlaying() public void EndPlaying(GameplayState state)
{ {
// This method is most commonly called via Dispose(), which is can be asynchronous (via the AsyncDisposalQueue). // This method is most commonly called via Dispose(), which is can be asynchronous (via the AsyncDisposalQueue).
// We probably need to find a better way to handle this... // We probably need to find a better way to handle this...
@ -163,6 +164,13 @@ namespace osu.Game.Online.Spectator
IsPlaying = false; IsPlaying = false;
currentBeatmap = null; currentBeatmap = null;
if (state.HasPassed)
currentState.State = SpectatingUserState.Completed;
else if (state.HasFailed)
currentState.State = SpectatingUserState.Failed;
else
currentState.State = SpectatingUserState.Quit;
EndPlayingInternal(currentState); EndPlayingInternal(currentState);
}); });
} }

View File

@ -24,14 +24,17 @@ namespace osu.Game.Online.Spectator
[Key(2)] [Key(2)]
public IEnumerable<APIMod> Mods { get; set; } = Enumerable.Empty<APIMod>(); public IEnumerable<APIMod> Mods { get; set; } = Enumerable.Empty<APIMod>();
[Key(3)]
public SpectatingUserState State { get; set; }
public bool Equals(SpectatorState other) public bool Equals(SpectatorState other)
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;
return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID; return BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID && State == other.State;
} }
public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID}"; public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID} State:{State}";
} }
} }

View File

@ -55,7 +55,9 @@ namespace osu.Game.Rulesets.UI
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
spectatorClient?.EndPlaying();
if (spectatorClient != null && gameplayState != null)
spectatorClient.EndPlaying(gameplayState);
} }
protected override void Update() protected override void Update()

View File

@ -1000,7 +1000,7 @@ namespace osu.Game.Screens.Play
// EndPlaying() is typically called from ReplayRecorder.Dispose(). Disposal is currently asynchronous. // EndPlaying() is typically called from ReplayRecorder.Dispose(). Disposal is currently asynchronous.
// To resolve test failures, forcefully end playing synchronously when this screen exits. // To resolve test failures, forcefully end playing synchronously when this screen exits.
// Todo: Replace this with a more permanent solution once osu-framework has a synchronous cleanup method. // Todo: Replace this with a more permanent solution once osu-framework has a synchronous cleanup method.
spectatorClient.EndPlaying(); spectatorClient.EndPlaying(GameplayState);
// GameplayClockContainer performs seeks / start / stop operations on the beatmap's track. // GameplayClockContainer performs seeks / start / stop operations on the beatmap's track.
// as we are no longer the current screen, we cannot guarantee the track is still usable. // as we are no longer the current screen, we cannot guarantee the track is still usable.