Skip to content

Commit

Permalink
Merge pull request #30525 from smoogipoo/multiplayer-refactor
Browse files Browse the repository at this point in the history
Replace `MultiplayerRoomComposite` with local bindings
  • Loading branch information
peppy authored Nov 7, 2024
2 parents cb2e5ac + 9f08b37 commit 54288c3
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 352 deletions.
23 changes: 12 additions & 11 deletions osu.Game.Tests/Visual/Multiplayer/TestSceneMatchStartControl.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System;
using System.Linq;
using Moq;
Expand Down Expand Up @@ -36,15 +34,18 @@ public partial class TestSceneMatchStartControl : OsuManualInputManagerTestScene
private readonly Bindable<BeatmapAvailability> beatmapAvailability = new Bindable<BeatmapAvailability>();
private readonly Bindable<Room> room = new Bindable<Room>();

private MultiplayerRoom multiplayerRoom;
private MultiplayerRoomUser localUser;
private OngoingOperationTracker ongoingOperationTracker;
private MultiplayerRoom multiplayerRoom = null!;
private MultiplayerRoomUser localUser = null!;
private OngoingOperationTracker ongoingOperationTracker = null!;

private PopoverContainer content;
private MatchStartControl control;
private PopoverContainer content = null!;
private MatchStartControl control = null!;

private OsuButton readyButton => control.ChildrenOfType<OsuButton>().Single();

[Cached(typeof(IBindable<PlaylistItem>))]
private readonly Bindable<PlaylistItem> currentItem = new Bindable<PlaylistItem>();

protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) =>
new CachedModelDependencyContainer<Room>(base.CreateChildDependencies(parent)) { Model = { BindTarget = room } };

Expand Down Expand Up @@ -112,15 +113,15 @@ public void SetUpSteps()
beatmapAvailability.Value = BeatmapAvailability.LocallyAvailable();
var playlistItem = new PlaylistItem(Beatmap.Value.BeatmapInfo)
currentItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID
};
room.Value = new Room
{
Playlist = { playlistItem },
CurrentPlaylistItem = { Value = playlistItem }
Playlist = { currentItem.Value },
CurrentPlaylistItem = { BindTarget = currentItem }
};
localUser = new MultiplayerRoomUser(API.LocalUser.Value.Id) { User = API.LocalUser.Value };
Expand All @@ -129,7 +130,7 @@ public void SetUpSteps()
{
Playlist =
{
TestMultiplayerClient.CreateMultiplayerPlaylistItem(playlistItem),
TestMultiplayerClient.CreateMultiplayerPlaylistItem(currentItem.Value),
},
Users = { localUser },
Host = localUser,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Multiplayer.Match;

namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneMultiplayerMatchFooter : MultiplayerTestScene
{
[Cached(typeof(IBindable<PlaylistItem>))]
private readonly Bindable<PlaylistItem> currentItem = new Bindable<PlaylistItem>();

public override void SetUpSteps()
{
base.SetUpSteps();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Platform;
Expand All @@ -29,10 +28,13 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneMultiplayerPlaylist : MultiplayerTestScene
{
private MultiplayerPlaylist list;
private BeatmapManager beatmaps;
private BeatmapSetInfo importedSet;
private BeatmapInfo importedBeatmap;
[Cached(typeof(IBindable<PlaylistItem>))]
private readonly Bindable<PlaylistItem> currentItem = new Bindable<PlaylistItem>();

private MultiplayerPlaylist list = null!;
private BeatmapManager beatmaps = null!;
private BeatmapSetInfo importedSet = null!;
private BeatmapInfo importedBeatmap = null!;

[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
Expand Down Expand Up @@ -198,7 +200,7 @@ public void TestInsertedItemDoesNotRefreshAllOthers()
addItemStep();
addItemStep();

DrawableRoomPlaylistItem[] drawableItems = null;
DrawableRoomPlaylistItem[] drawableItems = null!;
AddStep("get drawable items", () => drawableItems = this.ChildrenOfType<DrawableRoomPlaylistItem>().ToArray());

// Add 1 item for another user.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
Expand All @@ -28,13 +26,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneMultiplayerSpectateButton : MultiplayerTestScene
{
private MultiplayerSpectateButton spectateButton;
private MatchStartControl startControl;
[Cached(typeof(IBindable<PlaylistItem>))]
private readonly Bindable<PlaylistItem> currentItem = new Bindable<PlaylistItem>();

private readonly Bindable<PlaylistItem> selectedItem = new Bindable<PlaylistItem>();
private MultiplayerSpectateButton spectateButton = null!;
private MatchStartControl startControl = null!;

private BeatmapSetInfo importedSet;
private BeatmapManager beatmaps;
private BeatmapSetInfo importedSet = null!;
private BeatmapManager beatmaps = null!;

[BackgroundDependencyLoader]
private void load(GameHost host, AudioManager audio)
Expand All @@ -52,14 +51,12 @@ public override void SetUpSteps()

AddStep("create button", () =>
{
AvailabilityTracker.SelectedItem.BindTo(selectedItem);
AvailabilityTracker.SelectedItem.BindTo(currentItem);
importedSet = beatmaps.GetAllUsableBeatmapSets().First();
Beatmap.Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First());
selectedItem.Value = new PlaylistItem(Beatmap.Value.BeatmapInfo)
{
RulesetID = Beatmap.Value.BeatmapInfo.Ruleset.OnlineID,
};
currentItem.Value = SelectedRoom.Value.Playlist.First();
Child = new PopoverContainer
{
Expand Down
18 changes: 3 additions & 15 deletions osu.Game/Online/Multiplayer/MultiplayerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ await runOnUpdateThreadAsync(() =>
Debug.Assert(joinedRoom.Playlist.Count > 0);
APIRoom.Playlist.Clear();
APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(createPlaylistItem));
APIRoom.Playlist.AddRange(joinedRoom.Playlist.Select(item => new PlaylistItem(item)));
APIRoom.CurrentPlaylistItem.Value = APIRoom.Playlist.Single(item => item.ID == joinedRoom.Settings.PlaylistItemId);
// The server will null out the end date upon the host joining the room, but the null value is never communicated to the client.
Expand Down Expand Up @@ -734,7 +734,7 @@ public Task PlaylistItemAdded(MultiplayerPlaylistItem item)
Debug.Assert(APIRoom != null);
Room.Playlist.Add(item);
APIRoom.Playlist.Add(createPlaylistItem(item));
APIRoom.Playlist.Add(new PlaylistItem(item));
ItemAdded?.Invoke(item);
RoomUpdated?.Invoke();
Expand Down Expand Up @@ -780,7 +780,7 @@ public Task PlaylistItemChanged(MultiplayerPlaylistItem item)
int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID));
APIRoom.Playlist.RemoveAt(existingIndex);
APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item));
APIRoom.Playlist.Insert(existingIndex, new PlaylistItem(item));
}
catch (Exception ex)
{
Expand Down Expand Up @@ -853,18 +853,6 @@ private void updateLocalRoomSettings(MultiplayerRoomSettings settings)
RoomUpdated?.Invoke();
}

private PlaylistItem createPlaylistItem(MultiplayerPlaylistItem item) => new PlaylistItem(new APIBeatmap { OnlineID = item.BeatmapID, StarRating = item.StarRating })
{
ID = item.ID,
OwnerID = item.OwnerID,
RulesetID = item.RulesetID,
Expired = item.Expired,
PlaylistOrder = item.PlaylistOrder,
PlayedAt = item.PlayedAt,
RequiredMods = item.RequiredMods.ToArray(),
AllowedMods = item.AllowedMods.ToArray()
};

/// <summary>
/// For the provided user ID, update whether the user is included in <see cref="CurrentMatchPlayingUserIds"/>.
/// </summary>
Expand Down
39 changes: 39 additions & 0 deletions osu.Game/Online/Multiplayer/MultiplayerRoomExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using System.Linq;
using osu.Game.Online.Rooms;

namespace osu.Game.Online.Multiplayer
{
public static class MultiplayerRoomExtensions
{
/// <summary>
/// Returns all historical/expired items from the <paramref name="room"/>, in the order in which they were played.
/// </summary>
public static IEnumerable<MultiplayerPlaylistItem> GetHistoricalItems(this MultiplayerRoom room)
=> room.Playlist.Where(item => item.Expired).OrderBy(item => item.PlayedAt);

/// <summary>
/// Returns all non-expired items from the <paramref name="room"/>, in the order in which they are to be played.
/// </summary>
public static IEnumerable<MultiplayerPlaylistItem> GetUpcomingItems(this MultiplayerRoom room)
=> room.Playlist.Where(item => !item.Expired).OrderBy(item => item.PlaylistOrder);

/// <summary>
/// Returns the first non-expired <see cref="MultiplayerPlaylistItem"/> in playlist order from the supplied <paramref name="room"/>,
/// or the last-played <see cref="MultiplayerPlaylistItem"/> if all items are expired,
/// or <see langword="null"/> if <paramref name="room"/> was empty.
/// </summary>
public static MultiplayerPlaylistItem? GetCurrentItem(this MultiplayerRoom room)
{
if (room.Playlist.Count == 0)
return null;

return room.Playlist.All(item => item.Expired)
? GetHistoricalItems(room).Last()
: GetUpcomingItems(room).First();
}
}
}
38 changes: 28 additions & 10 deletions osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

#nullable disable

using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Online.Multiplayer;
using osuTK;

namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
public partial class RankRangePill : MultiplayerRoomComposite
public partial class RankRangePill : CompositeDrawable
{
private OsuTextFlowContainer rankFlow;
private OsuTextFlowContainer rankFlow = null!;

[Resolved]
private MultiplayerClient client { get; set; } = null!;

public RankRangePill()
{
Expand Down Expand Up @@ -55,20 +57,28 @@ private void load()
};
}

protected override void OnRoomUpdated()
protected override void LoadComplete()
{
base.OnRoomUpdated();
base.LoadComplete();

client.RoomUpdated += onRoomUpdated;
updateState();
}

private void onRoomUpdated() => Scheduler.AddOnce(updateState);

private void updateState()
{
rankFlow.Clear();

if (Room == null || Room.Users.All(u => u.User == null))
if (client.Room == null || client.Room.Users.All(u => u.User == null))
{
rankFlow.AddText("-");
return;
}

int minRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min();
int maxRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max();
int minRank = client.Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min();
int maxRank = client.Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max();

rankFlow.AddText("#");
rankFlow.AddText(minRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold));
Expand All @@ -78,5 +88,13 @@ protected override void OnRoomUpdated()
rankFlow.AddText("#");
rankFlow.AddText(maxRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold));
}

protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

if (client.IsNotNull())
client.RoomUpdated -= onRoomUpdated;
}
}
}
Loading

0 comments on commit 54288c3

Please sign in to comment.