Remove beatmap/ruleset/etc from MultiplayerRoomSettings

This commit is contained in:
smoogipoo
2021-10-22 16:48:28 +09:00
parent a1c9b56083
commit db87e42d47
11 changed files with 180 additions and 108 deletions

View File

@ -106,5 +106,17 @@ namespace osu.Game.Online.Multiplayer
/// Signals that the match has ended, all players have finished and results are ready to be displayed.
/// </summary>
Task ResultsReady();
/// <summary>
/// Signals that an item has been added to the playlist.
/// </summary>
/// <param name="item">The added item.</param>
Task PlaylistItemAdded(APIPlaylistItem item);
/// <summary>
/// Signals that an item has been removed from the playlist.
/// </summary>
/// <param name="item">The removed item.</param>
Task PlaylistItemRemoved(APIPlaylistItem item);
}
}

View File

@ -76,5 +76,17 @@ namespace osu.Game.Online.Multiplayer
/// <exception cref="NotJoinedRoomException">If the user is not in a room.</exception>
/// <exception cref="InvalidStateException">If an attempt to start the game occurs when the game's (or users') state disallows it.</exception>
Task StartMatch();
/// <summary>
/// Adds an item to the playlist.
/// </summary>
/// <param name="item">The item to add.</param>
Task AddPlaylistItem(APIPlaylistItem item);
/// <summary>
/// Removes an item from the playlist.
/// </summary>
/// <param name="item">The item to remove.</param>
Task RemovePlaylistItem(APIPlaylistItem item);
}
}

View File

@ -4,7 +4,6 @@
using System;
using MessagePack;
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Multiplayer.Queueing;
namespace osu.Game.Online.Multiplayer
{
@ -14,7 +13,6 @@ namespace osu.Game.Online.Multiplayer
[Serializable]
[MessagePackObject]
[Union(0, typeof(ChangeTeamRequest))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types.
[Union(1, typeof(EnqueuePlaylistItemRequest))]
public abstract class MatchUserRequest
{
}

View File

@ -301,6 +301,10 @@ namespace osu.Game.Online.Multiplayer
public abstract Task StartMatch();
public abstract Task AddPlaylistItem(APIPlaylistItem item);
public abstract Task RemovePlaylistItem(APIPlaylistItem item);
Task IMultiplayerClient.RoomStateChanged(MultiplayerRoomState state)
{
if (Room == null)
@ -416,11 +420,7 @@ namespace osu.Game.Online.Multiplayer
return Task.CompletedTask;
}
Task IMultiplayerClient.SettingsChanged(MultiplayerRoomSettings newSettings)
{
updateLocalRoomSettings(newSettings);
return Task.CompletedTask;
}
Task IMultiplayerClient.SettingsChanged(MultiplayerRoomSettings newSettings) => updateLocalRoomSettings(newSettings);
Task IMultiplayerClient.UserStateChanged(int userId, MultiplayerUserState state)
{
@ -572,6 +572,59 @@ namespace osu.Game.Online.Multiplayer
return Task.CompletedTask;
}
public async Task PlaylistItemAdded(APIPlaylistItem item)
{
if (Room == null)
return;
var set = await GetOnlineBeatmapSet(item.BeatmapID).ConfigureAwait(false);
var beatmap = set.Beatmaps.Single(b => b.OnlineBeatmapID == item.BeatmapID);
beatmap.MD5Hash = item.BeatmapChecksum;
var ruleset = Rulesets.GetRuleset(item.RulesetID);
await scheduleAsync(() =>
{
if (Room == null)
return;
Debug.Assert(APIRoom != null);
var playlistItem = new PlaylistItem
{
ID = item.ID,
Beatmap = { Value = beatmap },
Ruleset = { Value = ruleset },
};
var rulesetInstance = ruleset.CreateInstance();
playlistItem.RequiredMods.AddRange(item.RequiredMods.Select(m => m.ToMod(rulesetInstance)));
playlistItem.AllowedMods.AddRange(item.AllowedMods.Select(m => m.ToMod(rulesetInstance)));
APIRoom.Playlist.Add(playlistItem);
RoomUpdated?.Invoke();
}).ConfigureAwait(false);
}
public Task PlaylistItemRemoved(APIPlaylistItem item)
{
if (Room == null)
return Task.CompletedTask;
return scheduleAsync(() =>
{
if (Room == null)
return;
Debug.Assert(APIRoom != null);
APIRoom.Playlist.RemoveAll(i => i.ID == item.ID);
RoomUpdated?.Invoke();
});
}
/// <summary>
/// Populates the <see cref="User"/> for a given <see cref="MultiplayerRoomUser"/>.
/// </summary>
@ -597,62 +650,11 @@ namespace osu.Game.Online.Multiplayer
Room.Settings = settings;
APIRoom.Name.Value = Room.Settings.Name;
APIRoom.Password.Value = Room.Settings.Password;
// The current item update is delayed until an online beatmap lookup (below) succeeds.
// In-order for the client to not display an outdated beatmap, the current item is forcefully cleared here.
CurrentMatchPlayingItem.Value = null;
RoomUpdated?.Invoke();
GetOnlineBeatmapSet(settings.BeatmapID, cancellationToken).ContinueWith(set => Schedule(() =>
{
if (cancellationToken.IsCancellationRequested)
return;
updatePlaylist(settings, set.Result);
}), TaskContinuationOptions.OnlyOnRanToCompletion);
CurrentMatchPlayingItem.Value = APIRoom.Playlist.SingleOrDefault(p => p.ID == settings.PlaylistItemId);
}, cancellationToken);
private void updatePlaylist(MultiplayerRoomSettings settings, BeatmapSetInfo beatmapSet)
{
if (Room == null || !Room.Settings.Equals(settings))
return;
Debug.Assert(APIRoom != null);
var beatmap = beatmapSet.Beatmaps.Single(b => b.OnlineBeatmapID == settings.BeatmapID);
beatmap.MD5Hash = settings.BeatmapChecksum;
var ruleset = Rulesets.GetRuleset(settings.RulesetID).CreateInstance();
var mods = settings.RequiredMods.Select(m => m.ToMod(ruleset));
var allowedMods = settings.AllowedMods.Select(m => m.ToMod(ruleset));
// Try to retrieve the existing playlist item from the API room.
var playlistItem = APIRoom.Playlist.FirstOrDefault(i => i.ID == settings.PlaylistItemId);
if (playlistItem != null)
updateItem(playlistItem);
else
{
// An existing playlist item does not exist, so append a new one.
updateItem(playlistItem = new PlaylistItem());
APIRoom.Playlist.Add(playlistItem);
}
CurrentMatchPlayingItem.Value = playlistItem;
void updateItem(PlaylistItem item)
{
item.ID = settings.PlaylistItemId;
item.Beatmap.Value = beatmap;
item.Ruleset.Value = ruleset.RulesetInfo;
item.RequiredMods.Clear();
item.RequiredMods.AddRange(mods);
item.AllowedMods.Clear();
item.AllowedMods.AddRange(allowedMods);
}
}
/// <summary>
/// Retrieves a <see cref="BeatmapSetInfo"/> from an online source.
/// </summary>

View File

@ -4,10 +4,7 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using MessagePack;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer.Queueing;
using osu.Game.Online.Rooms;
@ -18,53 +15,29 @@ namespace osu.Game.Online.Multiplayer
public class MultiplayerRoomSettings : IEquatable<MultiplayerRoomSettings>
{
[Key(0)]
public int BeatmapID { get; set; }
[Key(1)]
public int RulesetID { get; set; }
[Key(2)]
public string BeatmapChecksum { get; set; } = string.Empty;
[Key(3)]
public string Name { get; set; } = "Unnamed room";
[Key(4)]
public IEnumerable<APIMod> RequiredMods { get; set; } = Enumerable.Empty<APIMod>();
[Key(5)]
public IEnumerable<APIMod> AllowedMods { get; set; } = Enumerable.Empty<APIMod>();
[Key(6)]
[Key(1)]
public long PlaylistItemId { get; set; }
[Key(7)]
[Key(2)]
public string Password { get; set; } = string.Empty;
[Key(8)]
[Key(3)]
public MatchType MatchType { get; set; } = MatchType.HeadToHead;
[Key(9)]
[Key(4)]
public QueueModes QueueMode { get; set; } = QueueModes.HostOnly;
public bool Equals(MultiplayerRoomSettings other)
=> BeatmapID == other.BeatmapID
&& BeatmapChecksum == other.BeatmapChecksum
&& RequiredMods.SequenceEqual(other.RequiredMods)
&& AllowedMods.SequenceEqual(other.AllowedMods)
&& RulesetID == other.RulesetID
&& Password.Equals(other.Password, StringComparison.Ordinal)
=> Password.Equals(other.Password, StringComparison.Ordinal)
&& Name.Equals(other.Name, StringComparison.Ordinal)
&& PlaylistItemId == other.PlaylistItemId
&& MatchType == other.MatchType
&& QueueMode == other.QueueMode;
public override string ToString() => $"Name:{Name}"
+ $" Beatmap:{BeatmapID} ({BeatmapChecksum})"
+ $" RequiredMods:{string.Join(',', RequiredMods)}"
+ $" AllowedMods:{string.Join(',', AllowedMods)}"
+ $" Password:{(string.IsNullOrEmpty(Password) ? "no" : "yes")}"
+ $" Ruleset:{RulesetID}"
+ $" Type:{MatchType}"
+ $" Item:{PlaylistItemId}"
+ $" Queue:{QueueMode}";

View File

@ -62,6 +62,8 @@ namespace osu.Game.Online.Multiplayer
connection.On<MatchRoomState>(nameof(IMultiplayerClient.MatchRoomStateChanged), ((IMultiplayerClient)this).MatchRoomStateChanged);
connection.On<int, MatchUserState>(nameof(IMultiplayerClient.MatchUserStateChanged), ((IMultiplayerClient)this).MatchUserStateChanged);
connection.On<MatchServerEvent>(nameof(IMultiplayerClient.MatchEvent), ((IMultiplayerClient)this).MatchEvent);
connection.On<APIPlaylistItem>(nameof(IMultiplayerClient.PlaylistItemAdded), ((IMultiplayerClient)this).PlaylistItemAdded);
connection.On<APIPlaylistItem>(nameof(IMultiplayerClient.PlaylistItemRemoved), ((IMultiplayerClient)this).PlaylistItemRemoved);
};
IsConnected.BindTo(connector.IsConnected);
@ -148,6 +150,22 @@ namespace osu.Game.Online.Multiplayer
return connection.InvokeAsync(nameof(IMultiplayerServer.StartMatch));
}
public override Task AddPlaylistItem(APIPlaylistItem item)
{
if (!IsConnected.Value)
return Task.CompletedTask;
return connection.InvokeAsync(nameof(IMultiplayerServer.AddPlaylistItem), item);
}
public override Task RemovePlaylistItem(APIPlaylistItem item)
{
if (!IsConnected.Value)
return Task.CompletedTask;
return connection.InvokeAsync(nameof(IMultiplayerServer.RemovePlaylistItem), item);
}
protected override Task<BeatmapSetInfo> GetOnlineBeatmapSet(int beatmapId, CancellationToken cancellationToken = default)
{
var tcs = new TaskCompletionSource<BeatmapSetInfo>();

View File

@ -1,30 +0,0 @@
// 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.
#nullable enable
using System.Collections.Generic;
using System.Linq;
using MessagePack;
using osu.Game.Online.API;
namespace osu.Game.Online.Multiplayer.Queueing
{
public class EnqueuePlaylistItemRequest : MatchUserRequest
{
[Key(0)]
public int BeatmapID { get; set; }
[Key(1)]
public int RulesetID { get; set; }
[Key(2)]
public string BeatmapChecksum { get; set; } = string.Empty;
[Key(3)]
public IEnumerable<APIMod> RequiredMods { get; set; } = Enumerable.Empty<APIMod>();
[Key(4)]
public IEnumerable<APIMod> AllowedMods { get; set; } = Enumerable.Empty<APIMod>();
}
}