1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-15 17:47:18 +08:00

Add spectator state object support

This commit is contained in:
Dean Herbert 2020-10-22 17:29:38 +09:00
parent 2021945a8c
commit 05697dfe68
5 changed files with 57 additions and 19 deletions

View File

@ -11,15 +11,15 @@ namespace osu.Game.Online.Spectator
/// Signals that a user has begun a new play session.
/// </summary>
/// <param name="userId">The user.</param>
/// <param name="beatmapId">The beatmap the user is playing.</param>
Task UserBeganPlaying(string userId, int beatmapId);
/// <param name="state">The state of gameplay.</param>
Task UserBeganPlaying(string userId, SpectatorState state);
/// <summary>
/// Signals that a user has finished a play session.
/// </summary>
/// <param name="userId">The user.</param>
/// <param name="beatmapId">The beatmap the user has finished playing.</param>
Task UserFinishedPlaying(string userId, int beatmapId);
/// <param name="state">The state of gameplay.</param>
Task UserFinishedPlaying(string userId, SpectatorState state);
/// <summary>
/// Called when new frames are available for a subscribed user's play session.

View File

@ -10,8 +10,8 @@ namespace osu.Game.Online.Spectator
/// <summary>
/// Signal the start of a new play session.
/// </summary>
/// <param name="beatmapId">The beatmap currently being played. Eventually this should be replaced with more complete metadata.</param>
Task BeginPlaySession(int beatmapId);
/// <param name="state">The state of gameplay.</param>
Task BeginPlaySession(SpectatorState state);
/// <summary>
/// Send a bundle of frame data for the current play session.
@ -22,15 +22,14 @@ namespace osu.Game.Online.Spectator
/// <summary>
/// Signal the end of a play session.
/// </summary>
/// <param name="beatmapId">The beatmap that was completed. This should be replaced with a play token once that flow is established.</param>
Task EndPlaySession(int beatmapId);
/// <param name="state">The state of gameplay.</param>
Task EndPlaySession(SpectatorState state);
/// <summary>
/// Request spectating data for the specified user. May be called on multiple users and offline users.
/// For offline users, a subscription will be created and data will begin streaming on next play.
/// </summary>
/// <param name="userId">The user to subscribe to.</param>
/// <returns></returns>
Task StartWatchingUser(string userId);
/// <summary>

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using osu.Game.Rulesets.Mods;
namespace osu.Game.Online.Spectator
{
[Serializable]
public class SpectatorState : IEquatable<SpectatorState>
{
public int? BeatmapID { get; set; }
[NotNull]
public IEnumerable<Mod> Mods { get; set; } = Enumerable.Empty<Mod>();
public SpectatorState(int? beatmapId = null, IEnumerable<Mod> mods = null)
{
BeatmapID = beatmapId;
if (mods != null)
Mods = mods;
}
public SpectatorState()
{
}
public bool Equals(SpectatorState other) => this.BeatmapID == other?.BeatmapID && this.Mods.SequenceEqual(other?.Mods);
public override string ToString() => $"Beatmap:{BeatmapID} Mods:{string.Join(',', Mods.SelectMany(m => m.Acronym))}";
}
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Types;
@ -30,6 +31,11 @@ namespace osu.Game.Online.Spectator
[Resolved]
private IBindable<WorkingBeatmap> beatmap { get; set; }
[Resolved]
private IBindable<IReadOnlyList<Mod>> mods { get; set; }
private readonly SpectatorState currentState = new SpectatorState();
[BackgroundDependencyLoader]
private void load()
{
@ -73,9 +79,9 @@ namespace osu.Game.Online.Spectator
.Build();
// until strong typed client support is added, each method must be manually bound (see https://github.com/dotnet/aspnetcore/issues/15198)
connection.On<string, int>(nameof(ISpectatorClient.UserBeganPlaying), ((ISpectatorClient)this).UserBeganPlaying);
connection.On<string, SpectatorState>(nameof(ISpectatorClient.UserBeganPlaying), ((ISpectatorClient)this).UserBeganPlaying);
connection.On<string, FrameDataBundle>(nameof(ISpectatorClient.UserSentFrames), ((ISpectatorClient)this).UserSentFrames);
connection.On<string, int>(nameof(ISpectatorClient.UserFinishedPlaying), ((ISpectatorClient)this).UserFinishedPlaying);
connection.On<string, SpectatorState>(nameof(ISpectatorClient.UserFinishedPlaying), ((ISpectatorClient)this).UserFinishedPlaying);
connection.Closed += async ex =>
{
@ -106,7 +112,7 @@ namespace osu.Game.Online.Spectator
}
}
Task ISpectatorClient.UserBeganPlaying(string userId, int beatmapId)
Task ISpectatorClient.UserBeganPlaying(string userId, SpectatorState state)
{
if (connection.ConnectionId != userId)
{
@ -123,15 +129,15 @@ namespace osu.Game.Online.Spectator
}
else
{
Console.WriteLine($"{connection.ConnectionId} Received user playing event for self {beatmapId}");
Console.WriteLine($"{connection.ConnectionId} Received user playing event for self {state}");
}
return Task.CompletedTask;
}
Task ISpectatorClient.UserFinishedPlaying(string userId, int beatmapId)
Task ISpectatorClient.UserFinishedPlaying(string userId, SpectatorState state)
{
Console.WriteLine($"{connection.ConnectionId} Received user finished event {beatmapId}");
Console.WriteLine($"{connection.ConnectionId} Received user finished event {state}");
return Task.CompletedTask;
}
@ -155,11 +161,11 @@ namespace osu.Game.Online.Spectator
connection.SendAsync(nameof(ISpectatorServer.SendFrameData), data);
}
public void EndPlaying(int beatmapId)
public void EndPlaying()
{
if (!isConnected) return;
connection.SendAsync(nameof(ISpectatorServer.EndPlaySession), beatmapId);
connection.SendAsync(nameof(ISpectatorServer.EndPlaySession), currentState);
}
public void WatchUser(string userId)
@ -171,6 +177,7 @@ namespace osu.Game.Online.Spectator
public void HandleFrame(ReplayFrame frame)
{
// ReSharper disable once SuspiciousTypeConversion.Global (implemented by rulesets)
if (frame is IConvertibleReplayFrame convertible)
// TODO: don't send a bundle for each individual frame
SendFrames(new FrameDataBundle(new[] { convertible.ToLegacy(beatmap.Value.Beatmap) }));

View File

@ -50,13 +50,13 @@ namespace osu.Game.Rulesets.UI
inputManager = GetContainingInputManager();
spectatorStreaming?.BeginPlaying(beatmap.Value.BeatmapInfo.ID);
spectatorStreaming?.BeginPlaying();
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
spectatorStreaming?.EndPlaying(beatmap.Value.BeatmapInfo.ID);
spectatorStreaming?.EndPlaying();
}
protected override bool OnMouseMove(MouseMoveEvent e)