diff --git a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
index 559db1675180..be30e06ed4b6 100644
--- a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
+++ b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
@@ -8,7 +8,6 @@
using osu.Framework.Testing;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Multiplayer;
-using osu.Game.Online.Rooms;
using osu.Game.Tests.Visual.Multiplayer;
namespace osu.Game.Tests.NonVisual.Multiplayer
@@ -72,10 +71,6 @@ public void TestPlayingUsersUpdatedOnJoin()
AddStep("create room initially in gameplay", () =>
{
- var newRoom = new Room();
- newRoom.CopyFrom(SelectedRoom.Value!);
-
- newRoom.RoomID = null;
MultiplayerClient.RoomSetupAction = room =>
{
room.State = MultiplayerRoomState.Playing;
@@ -86,7 +81,7 @@ public void TestPlayingUsersUpdatedOnJoin()
});
};
- RoomManager.CreateRoom(newRoom);
+ MultiplayerClient.JoinRoom(MultiplayerClient.ServerSideRooms.Single()).ConfigureAwait(false);
});
AddUntilStep("wait for room join", () => RoomJoined);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorList.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorList.cs
index 66c465cbedfa..bd1e15d06d29 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorList.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorList.cs
@@ -32,7 +32,7 @@ public void TestBasics()
Bindable playingState = new Bindable();
GameplayState gameplayState = new GameplayState(new Beatmap(), new OsuRuleset(), healthProcessor: new OsuHealthProcessor(0), localUserPlayingState: playingState);
TestSpectatorClient spectatorClient = new TestSpectatorClient();
- TestMultiplayerClient multiplayerClient = new TestMultiplayerClient(new TestMultiplayerRoomManager(new TestRoomRequestsHandler()));
+ TestMultiplayerClient multiplayerClient = new TestMultiplayerClient(new TestRoomRequestsHandler());
AddStep("create spectator list", () =>
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs
index c5fb52461a34..459a90d0960e 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableLoungeRoom.cs
@@ -38,7 +38,7 @@ public partial class TestSceneDrawableLoungeRoom : OsuManualInputManagerTestScen
[BackgroundDependencyLoader]
private void load()
{
- var mockLounge = new Mock();
+ var mockLounge = new Mock();
mockLounge
.Setup(l => l.Join(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>()))
.Callback, Action>((_, _, _, d) =>
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
index fb653cea8bd1..0966c61a3aa6 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs
@@ -58,7 +58,6 @@ public partial class TestSceneMultiplayer : ScreenTestScene
private TestMultiplayerComponents multiplayerComponents = null!;
private TestMultiplayerClient multiplayerClient => multiplayerComponents.MultiplayerClient;
- private TestMultiplayerRoomManager roomManager => multiplayerComponents.RoomManager;
[Resolved]
private OsuConfigManager config { get; set; } = null!;
@@ -257,7 +256,7 @@ public void TestExitMidJoin()
{
AddStep("create room", () =>
{
- roomManager.AddServerSideRoom(new Room
+ multiplayerClient.AddServerSideRoom(new Room
{
Name = "Test Room",
Playlist =
@@ -286,7 +285,7 @@ public void TestJoinRoomWithoutPassword()
{
AddStep("create room", () =>
{
- roomManager.AddServerSideRoom(new Room
+ multiplayerClient.AddServerSideRoom(new Room
{
Name = "Test Room",
Playlist =
@@ -336,7 +335,7 @@ public void TestJoinRoomWithPassword()
{
AddStep("create room", () =>
{
- roomManager.AddServerSideRoom(new Room
+ multiplayerClient.AddServerSideRoom(new Room
{
Name = "Test Room",
Password = "password",
@@ -789,7 +788,7 @@ public void TestRoomSettingsReQueriedWhenJoiningRoom()
{
AddStep("create room", () =>
{
- roomManager.AddServerSideRoom(new Room
+ multiplayerClient.AddServerSideRoom(new Room
{
Name = "Test Room",
QueueMode = QueueMode.AllPlayers,
@@ -810,8 +809,8 @@ public void TestRoomSettingsReQueriedWhenJoiningRoom()
AddStep("disable polling", () => this.ChildrenOfType().Single().TimeBetweenPolls.Value = 0);
AddStep("change server-side settings", () =>
{
- roomManager.ServerSideRooms[0].Name = "New name";
- roomManager.ServerSideRooms[0].Playlist =
+ multiplayerClient.ServerSideRooms[0].Name = "New name";
+ multiplayerClient.ServerSideRooms[0].Playlist =
[
new PlaylistItem(beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.Ruleset.OnlineID == 0)).BeatmapInfo)
{
@@ -828,7 +827,7 @@ public void TestRoomSettingsReQueriedWhenJoiningRoom()
AddAssert("local room has correct settings", () =>
{
var localRoom = this.ChildrenOfType().Single().Room;
- return localRoom.Name == roomManager.ServerSideRooms[0].Name && localRoom.Playlist.Single().ID == 2;
+ return localRoom.Name == multiplayerClient.ServerSideRooms[0].Name && localRoom.Playlist.Single().ID == 2;
});
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs
index 9951f62c77f6..eb649acd2d2a 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs
@@ -8,36 +8,33 @@
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Graphics.UserInterface;
-using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Lounge;
+using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Tests.Visual.OnlinePlay;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
- public partial class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene
+ public partial class TestSceneMultiplayerLoungeSubScreen : MultiplayerTestScene
{
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private LoungeSubScreen loungeScreen = null!;
- private Room? lastJoinedRoom;
- private string? lastJoinedPassword;
+
+ private RoomsContainer roomsContainer => loungeScreen.ChildrenOfType().First();
+
+ public TestSceneMultiplayerLoungeSubScreen()
+ : base(false)
+ {
+ }
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("push screen", () => LoadScreen(loungeScreen = new MultiplayerLoungeSubScreen()));
-
AddUntilStep("wait for present", () => loungeScreen.IsCurrentScreen());
-
- AddStep("bind to event", () =>
- {
- lastJoinedRoom = null;
- lastJoinedPassword = null;
- RoomManager.JoinRoomRequested = onRoomJoined;
- });
}
[Test]
@@ -47,8 +44,7 @@ public void TestJoinRoomWithoutPassword()
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("join room", () => InputManager.Key(Key.Enter));
- AddAssert("room join requested", () => lastJoinedRoom == RoomManager.Rooms.First());
- AddAssert("room join password correct", () => lastJoinedPassword == null);
+ AddAssert("room joined", () => MultiplayerClient.RoomJoined);
}
[Test]
@@ -67,6 +63,8 @@ public void TestPopoverHidesOnBackButton()
AddStep("hit escape", () => InputManager.Key(Key.Escape));
AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType().Any());
+
+ AddAssert("room not joined", () => !MultiplayerClient.RoomJoined);
}
[Test]
@@ -79,6 +77,8 @@ public void TestPopoverHidesOnLeavingScreen()
AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType().Any());
AddStep("exit screen", () => Stack.Exit());
AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType().Any());
+
+ AddAssert("room not joined", () => !MultiplayerClient.RoomJoined);
}
[Test]
@@ -93,9 +93,11 @@ public void TestJoinRoomWithIncorrectPasswordViaButton()
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "wrong");
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick());
- AddAssert("room not joined", () => loungeScreen.IsCurrentScreen());
+ AddAssert("still at lounge", () => loungeScreen.IsCurrentScreen());
AddUntilStep("password prompt still visible", () => passwordEntryPopover!.State.Value == Visibility.Visible);
AddAssert("textbox still focused", () => InputManager.FocusedDrawable is OsuPasswordTextBox);
+
+ AddAssert("room not joined", () => !MultiplayerClient.RoomJoined);
}
[Test]
@@ -110,9 +112,11 @@ public void TestJoinRoomWithIncorrectPasswordViaEnter()
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "wrong");
AddStep("press enter", () => InputManager.Key(Key.Enter));
- AddAssert("room not joined", () => loungeScreen.IsCurrentScreen());
+ AddAssert("still at lounge", () => loungeScreen.IsCurrentScreen());
AddUntilStep("password prompt still visible", () => passwordEntryPopover!.State.Value == Visibility.Visible);
AddAssert("textbox still focused", () => InputManager.FocusedDrawable is OsuPasswordTextBox);
+
+ AddAssert("room not joined", () => !MultiplayerClient.RoomJoined);
}
[Test]
@@ -127,8 +131,7 @@ public void TestJoinRoomWithCorrectPassword()
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password");
AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick());
- AddAssert("room join requested", () => lastJoinedRoom == RoomManager.Rooms.First());
- AddAssert("room join password correct", () => lastJoinedPassword == "password");
+ AddUntilStep("room joined", () => MultiplayerClient.RoomJoined);
}
[Test]
@@ -143,14 +146,9 @@ public void TestJoinRoomWithPasswordViaKeyboardOnly()
AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password");
AddStep("press enter", () => InputManager.Key(Key.Enter));
- AddAssert("room join requested", () => lastJoinedRoom == RoomManager.Rooms.First());
- AddAssert("room join password correct", () => lastJoinedPassword == "password");
+ AddAssert("room joined", () => MultiplayerClient.RoomJoined);
}
- private void onRoomJoined(Room room, string? password)
- {
- lastJoinedRoom = room;
- lastJoinedPassword = password;
- }
+ protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new MultiplayerTestSceneDependencies();
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
index 36f5bba38436..77b75f407b33 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs
@@ -127,7 +127,7 @@ public void TestListsClearedWhenRoomLeft()
addItemStep();
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
- AddStep("leave room", () => RoomManager.PartRoom());
+ AddStep("leave room", () => MultiplayerClient.LeaveRoom());
AddUntilStep("wait for room part", () => !RoomJoined);
AddUntilStep("item 0 not in lists", () => !inHistoryList(0) && !inQueueList(0));
@@ -148,7 +148,7 @@ public void TestQueueTabCount()
AddStep("finish current item", () => MultiplayerClient.FinishCurrentItem().WaitSafely());
assertQueueTabCount(2);
- AddStep("leave room", () => RoomManager.PartRoom());
+ AddStep("leave room", () => MultiplayerClient.LeaveRoom());
AddUntilStep("wait for room part", () => !RoomJoined);
assertQueueTabCount(0);
}
@@ -157,12 +157,12 @@ public void TestQueueTabCount()
[Test]
public void TestJoinRoomWithMixedItemsAddedInCorrectLists()
{
- AddStep("leave room", () => RoomManager.PartRoom());
+ AddStep("leave room", () => MultiplayerClient.LeaveRoom());
AddUntilStep("wait for room part", () => !RoomJoined);
AddStep("join room with items", () =>
{
- RoomManager.CreateRoom(new Room
+ API.Queue(new CreateRoomRequest(new Room
{
Name = "test name",
Playlist =
@@ -177,7 +177,7 @@ public void TestJoinRoomWithMixedItemsAddedInCorrectLists()
Expired = true
}
]
- });
+ }));
});
AddUntilStep("wait for room join", () => RoomJoined);
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs
index 8c8dc8d69ae6..53c7873de52a 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs
@@ -36,6 +36,7 @@ public override void SetUpSteps()
public void TestManyRooms()
{
AddStep("add rooms", () => RoomManager.AddRooms(500));
+ AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 500);
}
[Test]
@@ -75,6 +76,7 @@ public void TestScrollSelectedIntoView()
public void TestEnteringRoomTakesLeaseOnSelection()
{
AddStep("add rooms", () => RoomManager.AddRooms(1));
+ AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 1);
AddAssert("selected room is not disabled", () => !loungeScreen.SelectedRoom.Disabled);
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
index 58683314518e..51e39e1b7f95 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs
@@ -3,14 +3,13 @@
using System;
using NUnit.Framework;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
+using osu.Game.Online.API;
using osu.Game.Online.Rooms;
-using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Tests.Visual.OnlinePlay;
@@ -21,13 +20,33 @@ public partial class TestScenePlaylistsMatchSettingsOverlay : OnlinePlayTestScen
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private TestRoomSettings settings = null!;
-
- protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies();
+ private Func? handleRequest;
public override void SetUpSteps()
{
base.SetUpSteps();
+ AddStep("setup api", () =>
+ {
+ handleRequest = null;
+ ((DummyAPIAccess)API).HandleRequest = req =>
+ {
+ if (req is not CreateRoomRequest createReq || handleRequest == null)
+ return false;
+
+ if (handleRequest(createReq.Room) is string errorText)
+ createReq.TriggerFailure(new APIException(errorText, null));
+ else
+ {
+ var createdRoom = new APICreatedRoom();
+ createdRoom.CopyFrom(createReq.Room);
+ createReq.TriggerSuccess(createdRoom);
+ }
+
+ return true;
+ };
+ });
+
AddStep("create overlay", () =>
{
SelectedRoom.Value = new Room();
@@ -75,10 +94,10 @@ public void TestCorrectSettingsApplied()
settings.DurationField.Current.Value = expectedDuration;
SelectedRoom.Value!.Playlist = [new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo)];
- RoomManager.CreateRequested = r =>
+ handleRequest = r =>
{
createdRoom = r;
- return string.Empty;
+ return null;
};
});
@@ -103,7 +122,7 @@ public void TestInvalidBeatmapError()
errorMessage = $"{not_found_prefix} {beatmap.OnlineID}";
- RoomManager.CreateRequested = _ => errorMessage;
+ handleRequest = _ => errorMessage;
});
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
@@ -128,7 +147,7 @@ public void TestCreationFailureDisplaysError()
SelectedRoom.Value!.Name = "Test Room";
SelectedRoom.Value!.Playlist = [new PlaylistItem(CreateBeatmap(Ruleset.Value).BeatmapInfo)];
- RoomManager.CreateRequested = _ => failText;
+ handleRequest = _ => failText;
});
AddAssert("error not displayed", () => !settings.ErrorText.IsPresent);
@@ -159,48 +178,5 @@ public TestRoomSettings(Room room)
{
}
}
-
- private class TestDependencies : OnlinePlayTestSceneDependencies
- {
- protected override IRoomManager CreateRoomManager() => new TestRoomManager();
- }
-
- protected class TestRoomManager : IRoomManager
- {
- public Func? CreateRequested;
-
- public event Action RoomsUpdated
- {
- add { }
- remove { }
- }
-
- public IBindable InitialRoomsReceived { get; } = new Bindable(true);
-
- public IBindableList Rooms => null!;
-
- public void AddOrUpdateRoom(Room room) => throw new NotImplementedException();
-
- public void RemoveRoom(Room room) => throw new NotImplementedException();
-
- public void ClearRooms() => throw new NotImplementedException();
-
- public void CreateRoom(Room room, Action? onSuccess = null, Action? onError = null)
- {
- if (CreateRequested == null)
- return;
-
- string error = CreateRequested.Invoke(room);
-
- if (!string.IsNullOrEmpty(error))
- onError?.Invoke(error);
- else
- onSuccess?.Invoke(room);
- }
-
- public void JoinRoom(Room room, string? password, Action? onSuccess = null, Action? onError = null) => throw new NotImplementedException();
-
- public void PartRoom() => throw new NotImplementedException();
- }
}
}
diff --git a/osu.Game.Tests/Visual/TestMultiplayerComponents.cs b/osu.Game.Tests/Visual/TestMultiplayerComponents.cs
index 1814fb70c8a6..e385ff3a03a0 100644
--- a/osu.Game.Tests/Visual/TestMultiplayerComponents.cs
+++ b/osu.Game.Tests/Visual/TestMultiplayerComponents.cs
@@ -11,7 +11,6 @@
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens;
-using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Visual.Multiplayer;
using osu.Game.Tests.Visual.OnlinePlay;
@@ -26,15 +25,12 @@ namespace osu.Game.Tests.Visual
/// - Provides a to be resolved as a dependency in the screen,
/// which is typically a part of .
/// - Rebinds the to handle requests via a .
- /// - Provides a for the screen.
///
///
///
public partial class TestMultiplayerComponents : OsuScreen
{
- public Screens.OnlinePlay.Multiplayer.Multiplayer MultiplayerScreen => multiplayerScreen;
-
- public TestMultiplayerRoomManager RoomManager => multiplayerScreen.RoomManager;
+ public Screens.OnlinePlay.Multiplayer.Multiplayer MultiplayerScreen { get; }
public IScreen CurrentScreen => screenStack.CurrentScreen;
@@ -53,17 +49,17 @@ public partial class TestMultiplayerComponents : OsuScreen
private BeatmapManager beatmapManager { get; set; }
private readonly OsuScreenStack screenStack;
- private readonly TestMultiplayer multiplayerScreen;
+ private readonly TestRoomRequestsHandler requestsHandler = new TestRoomRequestsHandler();
public TestMultiplayerComponents()
{
- multiplayerScreen = new TestMultiplayer();
+ MultiplayerScreen = new Screens.OnlinePlay.Multiplayer.Multiplayer();
InternalChildren = new Drawable[]
{
userLookupCache,
beatmapLookupCache,
- MultiplayerClient = new TestMultiplayerClient(RoomManager),
+ MultiplayerClient = new TestMultiplayerClient(requestsHandler),
screenStack = new OsuScreenStack
{
Name = nameof(TestMultiplayerComponents),
@@ -71,13 +67,13 @@ public TestMultiplayerComponents()
}
};
- screenStack.Push(multiplayerScreen);
+ screenStack.Push(MultiplayerScreen);
}
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
- ((DummyAPIAccess)api).HandleRequest = request => multiplayerScreen.RequestsHandler.HandleRequest(request, api.LocalUser.Value, beatmapManager);
+ ((DummyAPIAccess)api).HandleRequest = request => requestsHandler.HandleRequest(request, api.LocalUser.Value, beatmapManager);
}
public override bool OnBackButton() => (screenStack.CurrentScreen as OsuScreen)?.OnBackButton() ?? base.OnBackButton();
@@ -90,13 +86,5 @@ public override bool OnExiting(ScreenExitEvent e)
screenStack.Exit();
return true;
}
-
- private partial class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer
- {
- public new TestMultiplayerRoomManager RoomManager { get; private set; }
- public TestRoomRequestsHandler RequestsHandler { get; private set; }
-
- protected override RoomManager CreateRoomManager() => RoomManager = new TestMultiplayerRoomManager(RequestsHandler = new TestRoomRequestsHandler());
- }
}
}
diff --git a/osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs
index f266c38b8b23..0ee9fa54cd81 100644
--- a/osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs
+++ b/osu.Game/Online/Multiplayer/IMultiplayerLoungeServer.cs
@@ -10,6 +10,13 @@ namespace osu.Game.Online.Multiplayer
///
public interface IMultiplayerLoungeServer
{
+ ///
+ /// Request to create a multiplayer room.
+ ///
+ /// The room to create.
+ /// The created multiplayer room.
+ Task CreateRoom(MultiplayerRoom room);
+
///
/// Request to join a multiplayer room.
///
diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
index 97161cce4816..6355710f631a 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
@@ -165,6 +165,15 @@ private void load()
private readonly TaskChain joinOrLeaveTaskChain = new TaskChain();
private CancellationTokenSource? joinCancellationSource;
+ public async Task CreateRoom(Room room)
+ {
+ if (Room != null)
+ throw new InvalidOperationException("Cannot create a multiplayer room while already in one.");
+
+ var cancellationSource = joinCancellationSource = new CancellationTokenSource();
+ await initRoom(room, r => CreateRoomInternal(new MultiplayerRoom(room)), cancellationSource.Token).ConfigureAwait(false);
+ }
+
///
/// Joins the for a given API .
///
@@ -175,33 +184,34 @@ public async Task JoinRoom(Room room, string? password = null)
if (Room != null)
throw new InvalidOperationException("Cannot join a multiplayer room while already in one.");
+ Debug.Assert(room.RoomID != null);
+
var cancellationSource = joinCancellationSource = new CancellationTokenSource();
+ await initRoom(room, r => JoinRoomInternal(room.RoomID.Value, password ?? room.Password), cancellationSource.Token).ConfigureAwait(false);
+ }
+ private async Task initRoom(Room room, Func> initFunc, CancellationToken cancellationToken)
+ {
await joinOrLeaveTaskChain.Add(async () =>
{
- Debug.Assert(room.RoomID != null);
-
- // Join the server-side room.
- var joinedRoom = await JoinRoom(room.RoomID.Value, password ?? room.Password).ConfigureAwait(false);
- Debug.Assert(joinedRoom != null);
+ // Initialise the server-side room.
+ MultiplayerRoom joinedRoom = await initFunc(room).ConfigureAwait(false);
// Populate users.
- Debug.Assert(joinedRoom.Users != null);
await PopulateUsers(joinedRoom.Users).ConfigureAwait(false);
// Update the stored room (must be done on update thread for thread-safety).
await runOnUpdateThreadAsync(() =>
{
Debug.Assert(Room == null);
+ Debug.Assert(APIRoom == null);
Room = joinedRoom;
APIRoom = room;
- Debug.Assert(joinedRoom.Playlist.Count > 0);
-
+ APIRoom.RoomID = joinedRoom.RoomID;
APIRoom.Playlist = joinedRoom.Playlist.Select(item => new PlaylistItem(item)).ToArray();
APIRoom.CurrentPlaylistItem = 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.
APIRoom.EndDate = null;
@@ -216,8 +226,8 @@ await runOnUpdateThreadAsync(() =>
postServerShuttingDownNotification();
OnRoomJoined();
- }, cancellationSource.Token).ConfigureAwait(false);
- }, cancellationSource.Token).ConfigureAwait(false);
+ }, cancellationToken).ConfigureAwait(false);
+ }, cancellationToken).ConfigureAwait(false);
}
///
@@ -227,16 +237,11 @@ protected virtual void OnRoomJoined()
{
}
- ///
- /// Joins the with a given ID.
- ///
- /// The room ID.
- /// An optional password to use when joining the room.
- /// The joined .
- protected abstract Task JoinRoom(long roomId, string? password = null);
-
public Task LeaveRoom()
{
+ if (Room == null)
+ return Task.CompletedTask;
+
// The join may have not completed yet, so certain tasks that either update the room or reference the room should be cancelled.
// This includes the setting of Room itself along with the initial update of the room settings on join.
joinCancellationSource?.Cancel();
@@ -260,6 +265,24 @@ public Task LeaveRoom()
});
}
+ ///
+ /// Creates the with the given settings.
+ ///
+ /// The room.
+ /// The joined
+ protected abstract Task CreateRoomInternal(MultiplayerRoom room);
+
+ ///
+ /// Joins the with a given ID.
+ ///
+ /// The room ID.
+ /// An optional password to use when joining the room.
+ /// The joined .
+ protected abstract Task JoinRoomInternal(long roomId, string? password = null);
+
+ ///
+ /// Leaves the currently-joined .
+ ///
protected abstract Task LeaveRoomInternal();
public abstract Task InvitePlayer(int userId);
diff --git a/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs b/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs
index d846e7f5669c..1cc5a8e70a80 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerClientExtensions.cs
@@ -5,6 +5,7 @@
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
+using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Logging;
namespace osu.Game.Online.Multiplayer
@@ -16,12 +17,8 @@ public static void FireAndForget(this Task task, Action? onSuccess = null, Actio
{
if (t.IsFaulted)
{
- Exception? exception = t.Exception;
-
- if (exception is AggregateException ae)
- exception = ae.InnerException;
-
- Debug.Assert(exception != null);
+ Debug.Assert(t.Exception != null);
+ Exception exception = t.Exception.AsSingular();
if (exception.GetHubExceptionMessage() is string message)
// Hub exceptions generally contain something we can show the user directly.
diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs
index 00048fa93197..f7bd4490ff6a 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerRoom.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerRoom.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using MessagePack;
using Newtonsoft.Json;
using osu.Game.Online.Rooms;
@@ -65,6 +66,14 @@ public MultiplayerRoom(long roomId)
RoomID = roomId;
}
+ public MultiplayerRoom(Room room)
+ {
+ RoomID = room.RoomID ?? 0;
+ Settings = new MultiplayerRoomSettings(room);
+ Host = room.Host != null ? new MultiplayerRoomUser(room.Host.OnlineID) : null;
+ Playlist = room.Playlist.Select(p => new MultiplayerPlaylistItem(p)).ToArray();
+ }
+
public override string ToString() => $"RoomID:{RoomID} Host:{Host?.UserID} Users:{Users.Count} State:{State} Settings: [{Settings}]";
}
}
diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs
index c73b02874ebd..c264ec1eefb6 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerRoomSettings.cs
@@ -35,6 +35,20 @@ public class MultiplayerRoomSettings : IEquatable
[IgnoreMember]
public bool AutoStartEnabled => AutoStartDuration != TimeSpan.Zero;
+ public MultiplayerRoomSettings()
+ {
+ }
+
+ public MultiplayerRoomSettings(Room room)
+ {
+ Name = room.Name;
+ Password = room.Password ?? string.Empty;
+ MatchType = room.Type;
+ QueueMode = room.QueueMode;
+ AutoStartDuration = room.AutoStartDuration;
+ AutoSkip = room.AutoSkip;
+ }
+
public bool Equals(MultiplayerRoomSettings? other)
{
if (ReferenceEquals(this, other)) return true;
diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
index a485a6b2626e..02e9cd4ee883 100644
--- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
@@ -76,7 +76,32 @@ private void load(IAPIProvider api)
}
}
- protected override async Task JoinRoom(long roomId, string? password = null)
+ protected override async Task CreateRoomInternal(MultiplayerRoom room)
+ {
+ if (!IsConnected.Value)
+ throw new OperationCanceledException();
+
+ Debug.Assert(connection != null);
+
+ try
+ {
+ return await connection.InvokeAsync(nameof(IMultiplayerServer.CreateRoom), room).ConfigureAwait(false);
+ }
+ catch (HubException exception)
+ {
+ if (exception.GetHubExceptionMessage() == HubClientConnector.SERVER_SHUTDOWN_MESSAGE)
+ {
+ Debug.Assert(connector != null);
+
+ await connector.Reconnect().ConfigureAwait(false);
+ return await CreateRoomInternal(room).ConfigureAwait(false);
+ }
+
+ throw;
+ }
+ }
+
+ protected override async Task JoinRoomInternal(long roomId, string? password = null)
{
if (!IsConnected.Value)
throw new OperationCanceledException();
@@ -94,7 +119,7 @@ protected override async Task JoinRoom(long roomId, string? pas
Debug.Assert(connector != null);
await connector.Reconnect().ConfigureAwait(false);
- return await JoinRoom(roomId, password).ConfigureAwait(false);
+ return await JoinRoomInternal(roomId, password).ConfigureAwait(false);
}
throw;
diff --git a/osu.Game/Online/Rooms/CreateRoomRequest.cs b/osu.Game/Online/Rooms/CreateRoomRequest.cs
index 63a3b7bfa8b6..5b2ea77aad66 100644
--- a/osu.Game/Online/Rooms/CreateRoomRequest.cs
+++ b/osu.Game/Online/Rooms/CreateRoomRequest.cs
@@ -15,6 +15,9 @@ public class CreateRoomRequest : APIRequest
public CreateRoomRequest(Room room)
{
Room = room;
+
+ // Also copy back to the source model, since it is likely to have been stored elsewhere.
+ Success += r => Room.CopyFrom(r);
}
protected override WebRequest CreateWebRequest()
@@ -23,7 +26,6 @@ protected override WebRequest CreateWebRequest()
req.ContentType = "application/json";
req.Method = HttpMethod.Post;
-
req.AddRaw(JsonConvert.SerializeObject(Room));
return req;
diff --git a/osu.Game/Online/Rooms/JoinRoomRequest.cs b/osu.Game/Online/Rooms/JoinRoomRequest.cs
index dfc7a53fb239..610e88724214 100644
--- a/osu.Game/Online/Rooms/JoinRoomRequest.cs
+++ b/osu.Game/Online/Rooms/JoinRoomRequest.cs
@@ -16,6 +16,9 @@ public JoinRoomRequest(Room room, string? password)
{
Room = room;
Password = password;
+
+ // Also copy back to the source model, since it is likely to have been stored elsewhere.
+ Success += r => Room.CopyFrom(r);
}
protected override WebRequest CreateWebRequest()
diff --git a/osu.Game/Online/Rooms/MultiplayerPlaylistItem.cs b/osu.Game/Online/Rooms/MultiplayerPlaylistItem.cs
index b737cda4bacf..4c4a3d97f235 100644
--- a/osu.Game/Online/Rooms/MultiplayerPlaylistItem.cs
+++ b/osu.Game/Online/Rooms/MultiplayerPlaylistItem.cs
@@ -66,5 +66,20 @@ public class MultiplayerPlaylistItem
public MultiplayerPlaylistItem()
{
}
+
+ public MultiplayerPlaylistItem(PlaylistItem item)
+ {
+ ID = item.ID;
+ OwnerID = item.OwnerID;
+ BeatmapID = item.Beatmap.OnlineID;
+ BeatmapChecksum = item.Beatmap.MD5Hash;
+ RulesetID = item.RulesetID;
+ RequiredMods = item.RequiredMods.ToArray();
+ AllowedMods = item.AllowedMods.ToArray();
+ Expired = item.Expired;
+ PlaylistOrder = item.PlaylistOrder ?? 0;
+ PlayedAt = item.PlayedAt;
+ StarRating = item.Beatmap.StarRating;
+ }
}
}
diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs
index f8660a656e6f..c5e292a19d35 100644
--- a/osu.Game/Online/Rooms/Room.cs
+++ b/osu.Game/Online/Rooms/Room.cs
@@ -342,6 +342,23 @@ public RoomAvailability Availability
// Not yet serialised (not implemented).
private RoomAvailability availability;
+ public Room()
+ {
+ }
+
+ public Room(MultiplayerRoom room)
+ {
+ RoomID = room.RoomID;
+ Name = room.Settings.Name;
+ Password = room.Settings.Password;
+ Type = room.Settings.MatchType;
+ QueueMode = room.Settings.QueueMode;
+ AutoStartDuration = room.Settings.AutoStartDuration;
+ AutoSkip = room.Settings.AutoSkip;
+ Host = room.Host != null ? new APIUser { Id = room.Host.UserID } : null;
+ Playlist = room.Playlist.Select(p => new PlaylistItem(p)).ToArray();
+ }
+
///
/// Copies values from another into this one.
///
diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
index 73f980f0a378..a1b61ea7a335 100644
--- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
+++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs
@@ -5,16 +5,15 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
-using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Development;
using osu.Framework.Graphics;
using osu.Framework.Logging;
-using osu.Game.Online.API;
using osu.Game.Online.Rooms;
namespace osu.Game.Screens.OnlinePlay.Components
{
+ // Todo: This class should be inlined into the lounge.
public partial class RoomManager : Component, IRoomManager
{
public event Action? RoomsUpdated;
@@ -23,89 +22,11 @@ public partial class RoomManager : Component, IRoomManager
public IBindableList Rooms => rooms;
- protected IBindable JoinedRoom => joinedRoom;
- private readonly Bindable joinedRoom = new Bindable();
-
- [Resolved]
- private IAPIProvider api { get; set; } = null!;
-
public RoomManager()
{
RelativeSizeAxes = Axes.Both;
}
- protected override void Dispose(bool isDisposing)
- {
- base.Dispose(isDisposing);
- PartRoom();
- }
-
- public virtual void CreateRoom(Room room, Action? onSuccess = null, Action? onError = null)
- {
- room.Host = api.LocalUser.Value;
-
- var req = new CreateRoomRequest(room);
-
- req.Success += result =>
- {
- joinedRoom.Value = room;
-
- AddOrUpdateRoom(result);
- room.CopyFrom(result); // Also copy back to the source model, since this is likely to have been stored elsewhere.
-
- // The server may not contain all properties (such as password), so invoke success with the given room.
- onSuccess?.Invoke(room);
- };
-
- req.Failure += exception =>
- {
- onError?.Invoke(req.Response?.Error ?? exception.Message);
- };
-
- api.Queue(req);
- }
-
- private JoinRoomRequest? currentJoinRoomRequest;
-
- public virtual void JoinRoom(Room room, string? password = null, Action? onSuccess = null, Action? onError = null)
- {
- currentJoinRoomRequest?.Cancel();
- currentJoinRoomRequest = new JoinRoomRequest(room, password);
-
- currentJoinRoomRequest.Success += result =>
- {
- joinedRoom.Value = room;
-
- AddOrUpdateRoom(result);
- room.CopyFrom(result); // Also copy back to the source model, since this is likely to have been stored elsewhere.
-
- onSuccess?.Invoke(room);
- };
-
- currentJoinRoomRequest.Failure += exception =>
- {
- if (exception is OperationCanceledException)
- return;
-
- onError?.Invoke(exception.Message);
- };
-
- api.Queue(currentJoinRoomRequest);
- }
-
- public virtual void PartRoom()
- {
- currentJoinRoomRequest?.Cancel();
-
- if (joinedRoom.Value == null)
- return;
-
- if (api.State.Value == APIState.Online)
- api.Queue(new PartRoomRequest(joinedRoom.Value));
-
- joinedRoom.Value = null;
- }
-
private readonly HashSet ignoredRooms = new HashSet();
public void AddOrUpdateRoom(Room room)
diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs
index 249cad8ca3df..6de11ec34c0f 100644
--- a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs
+++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallenge.cs
@@ -34,7 +34,6 @@
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
-using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.DailyChallenge.Events;
using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Screens.OnlinePlay.Match.Components;
@@ -71,9 +70,6 @@ public partial class DailyChallenge : OsuScreen, IPreviewTrackOwner, IHandlePres
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
- [Cached(Type = typeof(IRoomManager))]
- private RoomManager roomManager { get; set; }
-
[Cached]
private readonly OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker();
@@ -115,7 +111,6 @@ public DailyChallenge(Room room)
{
this.room = room;
playlistItem = room.Playlist.Single();
- roomManager = new RoomManager();
Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING };
}
@@ -131,7 +126,6 @@ private void load(AudioManager audio)
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
- roomManager,
beatmapAvailabilityTracker,
new ScreenStack(new RoomBackgroundScreen(playlistItem))
{
@@ -426,7 +420,7 @@ public override void OnEntering(ScreenTransitionEvent e)
base.OnEntering(e);
waves.Show();
- roomManager.JoinRoom(room);
+ API.Queue(new JoinRoomRequest(room, null));
startLoopingTrack(this, musicController);
metadataClient.BeginWatchingMultiplayerRoom(room.RoomID!.Value).ContinueWith(t =>
@@ -480,7 +474,7 @@ public override bool OnExiting(ScreenExitEvent e)
previewTrackManager.StopAnyPlaying(this);
this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
- roomManager.PartRoom();
+ API.Queue(new PartRoomRequest(room));
metadataClient.EndWatchingMultiplayerRoom(room.RoomID!.Value).FireAndForget();
return base.OnExiting(e);
diff --git a/osu.Game/Screens/OnlinePlay/IRoomManager.cs b/osu.Game/Screens/OnlinePlay/IRoomManager.cs
index ed4fb7b15e69..8ecb1dd7e0e9 100644
--- a/osu.Game/Screens/OnlinePlay/IRoomManager.cs
+++ b/osu.Game/Screens/OnlinePlay/IRoomManager.cs
@@ -38,27 +38,5 @@ public interface IRoomManager
/// Removes all s from this .
///
void ClearRooms();
-
- ///
- /// Creates a new .
- ///
- /// The to create.
- /// An action to be invoked if the creation succeeds.
- /// An action to be invoked if an error occurred.
- void CreateRoom(Room room, Action? onSuccess = null, Action? onError = null);
-
- ///
- /// Joins a .
- ///
- /// The to join. must be populated.
- /// An optional password to use for the join operation.
- ///
- ///
- void JoinRoom(Room room, string? password = null, Action? onSuccess = null, Action? onError = null);
-
- ///
- /// Parts the currently-joined .
- ///
- void PartRoom();
}
}
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs
index 1cabb22e300d..d369722e5f6c 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs
@@ -24,7 +24,6 @@
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Input.Bindings;
using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Screens.OnlinePlay.Components;
@@ -51,7 +50,7 @@ public required Bindable SelectedRoom
}
[Resolved(canBeNull: true)]
- private LoungeSubScreen? lounge { get; set; }
+ private IOnlinePlayLounge? lounge { get; set; }
[Resolved]
private IDialogOverlay? dialogOverlay { get; set; }
@@ -170,12 +169,7 @@ public override MenuItem[] ContextMenuItems
{
items.Add(new OsuMenuItem("Close playlist", MenuItemType.Destructive, () =>
{
- dialogOverlay?.Push(new ClosePlaylistDialog(Room, () =>
- {
- var request = new ClosePlaylistRequest(Room.RoomID!.Value);
- request.Success += () => lounge?.RefreshRooms();
- api.Queue(request);
- }));
+ dialogOverlay?.Push(new ClosePlaylistDialog(Room, () => lounge?.Close(Room)));
}));
}
@@ -238,7 +232,7 @@ public partial class PasswordEntryPopover : OsuPopover
private readonly Room room;
[Resolved(canBeNull: true)]
- private LoungeSubScreen? lounge { get; set; }
+ private IOnlinePlayLounge? lounge { get; set; }
public override bool HandleNonPositionalInput => true;
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/IOnlinePlayLounge.cs b/osu.Game/Screens/OnlinePlay/Lounge/IOnlinePlayLounge.cs
new file mode 100644
index 000000000000..73ab84af13b3
--- /dev/null
+++ b/osu.Game/Screens/OnlinePlay/Lounge/IOnlinePlayLounge.cs
@@ -0,0 +1,32 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Game.Online.Rooms;
+
+namespace osu.Game.Screens.OnlinePlay.Lounge
+{
+ public interface IOnlinePlayLounge
+ {
+ ///
+ /// Attempts to join the given room.
+ ///
+ /// The room to join.
+ /// The password.
+ /// A delegate to invoke if the user joined the room.
+ /// A delegate to invoke if the user is not able join the room.
+ void Join(Room room, string? password, Action? onSuccess = null, Action? onFailure = null);
+
+ ///
+ /// Copies the given room and opens it as a fresh (not-yet-created) one.
+ ///
+ /// The room to copy.
+ void OpenCopy(Room room);
+
+ ///
+ /// Closes the given room.
+ ///
+ /// The room to close.
+ void Close(Room room);
+ }
+}
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs
index f00cf7427c0a..0e08e398a494 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs
@@ -21,6 +21,7 @@
using osu.Game.Graphics.UserInterface;
using osu.Game.Input;
using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Rulesets;
@@ -33,7 +34,8 @@
namespace osu.Game.Screens.OnlinePlay.Lounge
{
[Cached]
- public abstract partial class LoungeSubScreen : OnlinePlaySubScreen
+ [Cached(typeof(IOnlinePlayLounge))]
+ public abstract partial class LoungeSubScreen : OnlinePlaySubScreen, IOnlinePlayLounge
{
public override string Title => "Lounge";
@@ -263,6 +265,9 @@ public override void OnResuming(ScreenTransitionEvent e)
music.EnsurePlayingSomething();
onReturning();
+
+ // Poll for any newly-created rooms (including potentially the user's own).
+ ListingPollingComponent.PollImmediately();
}
public override bool OnExiting(ScreenExitEvent e)
@@ -297,14 +302,14 @@ private void onLeaving()
popoverContainer.HidePopover();
}
- public virtual void Join(Room room, string? password, Action? onSuccess = null, Action? onFailure = null) => Schedule(() =>
+ public void Join(Room room, string? password, Action? onSuccess = null, Action? onFailure = null) => Schedule(() =>
{
if (joiningRoomOperation != null)
return;
joiningRoomOperation = ongoingOperationTracker?.BeginOperation();
- RoomManager?.JoinRoom(room, password, _ =>
+ JoinInternal(room, password, r =>
{
Open(room);
joiningRoomOperation?.Dispose();
@@ -318,10 +323,8 @@ public virtual void Join(Room room, string? password, Action? onSuccess =
});
});
- ///
- /// Copies a room and opens it as a fresh (not-yet-created) one.
- ///
- /// The room to copy.
+ protected abstract void JoinInternal(Room room, string? password, Action onSuccess, Action onFailure);
+
public void OpenCopy(Room room)
{
Debug.Assert(room.RoomID != null);
@@ -358,6 +361,15 @@ public void OpenCopy(Room room)
api.Queue(req);
}
+ public void Close(Room room)
+ {
+ Debug.Assert(room.RoomID != null);
+
+ var request = new ClosePlaylistRequest(room.RoomID.Value);
+ request.Success += RefreshRooms;
+ api.Queue(request);
+ }
+
///
/// Push a room as a new subscreen.
///
diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
index ce51bb3c2172..cfb2be1189e0 100644
--- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs
@@ -361,7 +361,9 @@ public override bool OnExiting(ScreenExitEvent e)
if (!ensureExitConfirmed())
return true;
- RoomManager?.PartRoom();
+ if (Room.RoomID != null)
+ PartRoom();
+
Mods.Value = Array.Empty();
onLeaving();
@@ -369,6 +371,11 @@ public override bool OnExiting(ScreenExitEvent e)
return base.OnExiting(e);
}
+ ///
+ /// Parts from the current room.
+ ///
+ protected abstract void PartRoom();
+
private bool ensureExitConfirmed()
{
if (ExitConfirmed)
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs
index 137205414901..eda3bace40a7 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs
@@ -29,12 +29,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
{
public partial class MultiplayerMatchSettingsOverlay : RoomSettingsOverlay
{
- public required Bindable SelectedItem
- {
- get => selectedItem;
- set => selectedItem.Current = value;
- }
-
protected override OsuButton SubmitButton => settings.ApplyButton;
protected override bool IsLoading => ongoingOperationTracker.InProgress.Value;
@@ -56,7 +50,6 @@ public MultiplayerMatchSettingsOverlay(Room room)
RelativeSizeAxes = Axes.Both,
RelativePositionAxes = Axes.Y,
SettingsApplied = Hide,
- SelectedItem = { BindTarget = SelectedItem }
};
protected partial class MatchSettings : CompositeDrawable
@@ -65,7 +58,6 @@ protected partial class MatchSettings : CompositeDrawable
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
- public readonly Bindable SelectedItem = new Bindable();
public Action? SettingsApplied;
public OsuTextBox NameField = null!;
@@ -86,9 +78,6 @@ protected partial class MatchSettings : CompositeDrawable
[Resolved]
private MultiplayerMatchSubScreen matchSubScreen { get; set; } = null!;
- [Resolved]
- private IRoomManager manager { get; set; } = null!;
-
[Resolved]
private MultiplayerClient client { get; set; } = null!;
@@ -279,7 +268,6 @@ private void load(OverlayColourProvider colourProvider, OsuColour colours)
{
RelativeSizeAxes = Axes.X,
Height = DrawableRoomPlaylistItem.HEIGHT,
- SelectedItem = { BindTarget = SelectedItem }
},
selectBeatmapButton = new RoundedButton
{
@@ -475,32 +463,26 @@ private void apply()
.ContinueWith(t => Schedule(() =>
{
if (t.IsCompletedSuccessfully)
- onSuccess(room);
+ onSuccess();
else
- onError(t.Exception?.AsSingular().Message ?? "Error changing settings.");
+ onError(t.Exception, "Error changing settings");
}));
}
else
{
- room.Name = NameField.Text;
- room.Type = TypePicker.Current.Value;
- room.Password = PasswordTextBox.Current.Value;
- room.QueueMode = QueueModeDropdown.Current.Value;
- room.AutoStartDuration = TimeSpan.FromSeconds((int)startModeDropdown.Current.Value);
- room.AutoSkip = AutoSkipCheckbox.Current.Value;
-
- if (int.TryParse(MaxParticipantsField.Text, out int max))
- room.MaxParticipants = max;
- else
- room.MaxParticipants = null;
-
- manager.CreateRoom(room, onSuccess, onError);
+ client.CreateRoom(room).ContinueWith(t => Schedule(() =>
+ {
+ if (t.IsCompletedSuccessfully)
+ onSuccess();
+ else
+ onError(t.Exception, "Error creating room");
+ }));
}
}
private void hideError() => ErrorText.FadeOut(50);
- private void onSuccess(Room room) => Schedule(() =>
+ private void onSuccess() => Schedule(() =>
{
Debug.Assert(applyingSettingsOperation != null);
@@ -510,28 +492,34 @@ private void onSuccess(Room room) => Schedule(() =>
applyingSettingsOperation = null;
});
- private void onError(string text) => Schedule(() =>
+ private void onError(Exception? exception, string description)
{
- Debug.Assert(applyingSettingsOperation != null);
+ if (exception is AggregateException aggregateException)
+ exception = aggregateException.AsSingular();
- // see https://github.com/ppy/osu-web/blob/2c97aaeb64fb4ed97c747d8383a35b30f57428c7/app/Models/Multiplayer/PlaylistItem.php#L48.
- const string not_found_prefix = "beatmaps not found:";
+ string message = exception?.GetHubExceptionMessage() ?? $"{description} ({exception?.Message})";
- if (text.StartsWith(not_found_prefix, StringComparison.Ordinal))
- {
- ErrorText.Text = "The selected beatmap is not available online.";
- SelectedItem.Value?.MarkInvalid();
- }
- else
+ Schedule(() =>
{
- ErrorText.Text = text;
- }
+ Debug.Assert(applyingSettingsOperation != null);
- ErrorText.FadeIn(50);
+ // see https://github.com/ppy/osu-web/blob/2c97aaeb64fb4ed97c747d8383a35b30f57428c7/app/Models/Multiplayer/PlaylistItem.php#L48.
+ const string not_found_prefix = "beatmaps not found:";
- applyingSettingsOperation.Dispose();
- applyingSettingsOperation = null;
- });
+ if (message.StartsWith(not_found_prefix, StringComparison.Ordinal))
+ {
+ ErrorText.Text = "The selected beatmap is not available online.";
+ room.Playlist.SingleOrDefault()?.MarkInvalid();
+ }
+ else
+ ErrorText.Text = message;
+
+ ErrorText.FadeIn(50);
+
+ applyingSettingsOperation.Dispose();
+ applyingSettingsOperation = null;
+ });
+ }
protected override void Dispose(bool isDisposing)
{
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs
index bf316bb3da5b..dfed32aebccd 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs
@@ -8,7 +8,6 @@
using osu.Framework.Screens;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
-using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
namespace osu.Game.Screens.OnlinePlay.Multiplayer
@@ -97,8 +96,6 @@ private void transitionFromResults()
protected override string ScreenTitle => "Multiplayer";
- protected override RoomManager CreateRoomManager() => new MultiplayerRoomManager();
-
protected override LoungeSubScreen CreateLounge() => new MultiplayerLoungeSubScreen();
public void Join(Room room, string? password) => Schedule(() => Lounge.Join(room, password));
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs
index dd61caa3db37..873a9cde8896 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs
@@ -1,12 +1,13 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Logging;
-using osu.Framework.Screens;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Configuration;
@@ -32,19 +33,6 @@ public partial class MultiplayerLoungeSubScreen : LoungeSubScreen
private Dropdown roomAccessTypeDropdown = null!;
private OsuCheckbox showInProgress = null!;
- public override void OnResuming(ScreenTransitionEvent e)
- {
- base.OnResuming(e);
-
- // Upon having left a room, we don't know whether we were the only participant, and whether the room is now closed as a result of leaving it.
- // To work around this, temporarily remove the room and trigger an immediate listing poll.
- if (e.Last is MultiplayerMatchSubScreen match)
- {
- RoomManager?.RemoveRoom(match.Room);
- ListingPollingComponent.PollImmediately();
- }
- }
-
protected override IEnumerable CreateFilterControls()
{
foreach (var control in base.CreateFilterControls())
@@ -93,6 +81,24 @@ protected override FilterCriteria CreateFilterCriteria()
protected override ListingPollingComponent CreatePollingComponent() => new MultiplayerListingPollingComponent();
+ protected override void JoinInternal(Room room, string? password, Action onSuccess, Action onFailure)
+ {
+ client.JoinRoom(room, password).ContinueWith(result =>
+ {
+ if (result.IsCompletedSuccessfully)
+ onSuccess(room);
+ else
+ {
+ const string message = "Failed to join multiplayer room.";
+
+ if (result.Exception != null)
+ Logger.Error(result.Exception, message);
+
+ onFailure.Invoke(result.Exception?.AsSingular().Message ?? message);
+ }
+ });
+ }
+
protected override void OpenNewRoom(Room room)
{
if (!client.IsConnected.Value)
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs
index b803c5f28b12..b0ee0644a75a 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs
@@ -266,10 +266,7 @@ protected override void OpenStyleSelection()
SelectedItem = SelectedItem
};
- protected override RoomSettingsOverlay CreateRoomSettingsOverlay(Room room) => new MultiplayerMatchSettingsOverlay(room)
- {
- SelectedItem = SelectedItem
- };
+ protected override RoomSettingsOverlay CreateRoomSettingsOverlay(Room room) => new MultiplayerMatchSettingsOverlay(room);
protected override APIMod[] GetGameplayMods()
{
@@ -320,6 +317,8 @@ public override bool OnExiting(ScreenExitEvent e)
return base.OnExiting(e);
}
+ protected override void PartRoom() => client.LeaveRoom();
+
private ModSettingChangeTracker? modSettingChangeTracker;
private ScheduledDelegate? debouncedModSettingsUpdate;
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs
deleted file mode 100644
index 7f09c9cbe972..000000000000
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Diagnostics;
-using osu.Framework.Allocation;
-using osu.Framework.Extensions.ExceptionExtensions;
-using osu.Framework.Logging;
-using osu.Game.Online.Multiplayer;
-using osu.Game.Online.Rooms;
-using osu.Game.Screens.OnlinePlay.Components;
-
-namespace osu.Game.Screens.OnlinePlay.Multiplayer
-{
- public partial class MultiplayerRoomManager : RoomManager
- {
- [Resolved]
- private MultiplayerClient multiplayerClient { get; set; } = null!;
-
- public override void CreateRoom(Room room, Action? onSuccess = null, Action? onError = null)
- => base.CreateRoom(room, r => joinMultiplayerRoom(r, r.Password, onSuccess, onError), onError);
-
- public override void JoinRoom(Room room, string? password = null, Action? onSuccess = null, Action? onError = null)
- {
- if (!multiplayerClient.IsConnected.Value)
- {
- onError?.Invoke("Not currently connected to the multiplayer server.");
- return;
- }
-
- // this is done here as a pre-check to avoid clicking on already closed rooms in the lounge from triggering a server join.
- // should probably be done at a higher level, but due to the current structure of things this is the easiest place for now.
- if (room.HasEnded)
- {
- onError?.Invoke("Cannot join an ended room.");
- return;
- }
-
- base.JoinRoom(room, password, r => joinMultiplayerRoom(r, password, onSuccess, onError), onError);
- }
-
- public override void PartRoom()
- {
- if (JoinedRoom.Value == null)
- return;
-
- base.PartRoom();
- multiplayerClient.LeaveRoom();
- }
-
- private void joinMultiplayerRoom(Room room, string? password, Action? onSuccess = null, Action? onError = null)
- {
- Debug.Assert(room.RoomID != null);
-
- multiplayerClient.JoinRoom(room, password).ContinueWith(t =>
- {
- if (t.IsCompletedSuccessfully)
- Schedule(() => onSuccess?.Invoke(room));
- else if (t.IsFaulted)
- {
- const string message = "Failed to join multiplayer room.";
-
- if (t.Exception != null)
- Logger.Error(t.Exception, message);
-
- PartRoom();
- Schedule(() => onError?.Invoke(t.Exception?.AsSingular().Message ?? message));
- }
- });
- }
- }
-}
diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs
index 17fb667e1400..8988c82deed3 100644
--- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs
@@ -36,12 +36,12 @@ public abstract partial class OnlinePlayScreen : OsuScreen, IHasSubScreenStack
private readonly ScreenStack screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both };
private OnlinePlayScreenWaveContainer waves = null!;
- [Cached(Type = typeof(IRoomManager))]
- protected RoomManager RoomManager { get; private set; }
-
[Cached]
private readonly OngoingOperationTracker ongoingOperationTracker = new OngoingOperationTracker();
+ [Cached(Type = typeof(IRoomManager))]
+ private readonly RoomManager roomManager = new RoomManager();
+
[Resolved]
protected IAPIProvider API { get; private set; } = null!;
@@ -51,8 +51,6 @@ protected OnlinePlayScreen()
Origin = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING };
-
- RoomManager = CreateRoomManager();
}
private readonly IBindable apiState = new Bindable();
@@ -67,7 +65,7 @@ private void load()
{
screenStack,
new Header(ScreenTitle, screenStack),
- RoomManager,
+ roomManager,
ongoingOperationTracker,
}
};
@@ -165,8 +163,6 @@ public override bool OnExiting(ScreenExitEvent e)
subScreen.Exit();
}
- RoomManager.PartRoom();
-
waves.Hide();
this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
@@ -224,8 +220,6 @@ private void subScreenChanged(IScreen lastScreen, IScreen newScreen)
protected abstract string ScreenTitle { get; }
- protected virtual RoomManager CreateRoomManager() => new RoomManager();
-
protected abstract LoungeSubScreen CreateLounge();
ScreenStack IHasSubScreenStack.SubScreenStack => screenStack;
diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs
index fa1ee004c9bc..9b35a794a30a 100644
--- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Screens;
@@ -15,9 +14,6 @@ public abstract partial class OnlinePlaySubScreen : OsuScreen, IOnlinePlaySubScr
protected sealed override bool PlayExitSound => false;
- [Resolved]
- protected IRoomManager? RoomManager { get; private set; }
-
protected OnlinePlaySubScreen()
{
Anchor = Anchor.Centre;
diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs
index d66b4f844c48..6ed367328c1d 100644
--- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
@@ -59,6 +60,20 @@ protected override FilterCriteria CreateFilterCriteria()
return criteria;
}
+ protected override void JoinInternal(Room room, string? password, Action onSuccess, Action onFailure)
+ {
+ var joinRoomRequest = new JoinRoomRequest(room, password);
+
+ joinRoomRequest.Success += r => onSuccess(r);
+ joinRoomRequest.Failure += exception =>
+ {
+ if (exception is not OperationCanceledException)
+ onFailure(exception.Message);
+ };
+
+ api.Queue(joinRoomRequest);
+ }
+
protected override OsuButton CreateNewRoomButton() => new CreatePlaylistsRoomButton();
protected override Room CreateNewRoom()
diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs
index 88af161cc847..b3d1d577ed67 100644
--- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs
+++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs
@@ -75,9 +75,6 @@ protected partial class MatchSettings : CompositeDrawable
private PurpleRoundedButton editPlaylistButton = null!;
- [Resolved]
- private IRoomManager? manager { get; set; }
-
[Resolved]
private IAPIProvider api { get; set; } = null!;
@@ -449,7 +446,11 @@ private void apply()
room.Duration = DurationField.Current.Value;
loadingLayer.Show();
- manager?.CreateRoom(room, onSuccess, onError);
+
+ var req = new CreateRoomRequest(room);
+ req.Success += onSuccess;
+ req.Failure += e => onError(req.Response?.Error ?? e.Message);
+ api.Queue(req);
}
private void hideError() => ErrorText.FadeOut(50);
diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs
index 2195ed472261..bf0e428483e0 100644
--- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs
@@ -342,6 +342,8 @@ private void closePlaylist()
}));
}
+ protected override void PartRoom() => api.Queue(new PartRoomRequest(Room));
+
protected override Screen CreateGameplayScreen(PlaylistItem selectedItem)
{
return new PlayerLoader(() => new PlaylistsPlayer(Room, selectedItem)
diff --git a/osu.Game/Tests/Visual/Multiplayer/IMultiplayerTestSceneDependencies.cs b/osu.Game/Tests/Visual/Multiplayer/IMultiplayerTestSceneDependencies.cs
index efd0b80ebf96..262816ae89b7 100644
--- a/osu.Game/Tests/Visual/Multiplayer/IMultiplayerTestSceneDependencies.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/IMultiplayerTestSceneDependencies.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Screens.OnlinePlay;
using osu.Game.Tests.Visual.OnlinePlay;
using osu.Game.Tests.Visual.Spectator;
@@ -17,11 +16,6 @@ public interface IMultiplayerTestSceneDependencies : IOnlinePlayTestSceneDepende
///
TestMultiplayerClient MultiplayerClient { get; }
- ///
- /// The cached .
- ///
- new TestMultiplayerRoomManager RoomManager { get; }
-
///
/// The cached .
///
diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs
index 42cf31782946..d1497d5142ce 100644
--- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs
@@ -17,7 +17,6 @@ public abstract partial class MultiplayerTestScene : OnlinePlayTestScene, IMulti
public const int PLAYER_2_ID = 56;
public TestMultiplayerClient MultiplayerClient => OnlinePlayDependencies.MultiplayerClient;
- public new TestMultiplayerRoomManager RoomManager => OnlinePlayDependencies.RoomManager;
public TestSpectatorClient SpectatorClient => OnlinePlayDependencies.SpectatorClient;
protected new MultiplayerTestSceneDependencies OnlinePlayDependencies => (MultiplayerTestSceneDependencies)base.OnlinePlayDependencies;
@@ -56,7 +55,7 @@ public override void SetUpSteps()
AddStep("join room", () =>
{
SelectedRoom.Value = CreateRoom();
- RoomManager.CreateRoom(SelectedRoom.Value);
+ MultiplayerClient.CreateRoom(SelectedRoom.Value).ConfigureAwait(false);
});
AddUntilStep("wait for room join", () => RoomJoined);
diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestSceneDependencies.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestSceneDependencies.cs
index 88202d432764..24c33f2f49f5 100644
--- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestSceneDependencies.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestSceneDependencies.cs
@@ -3,7 +3,6 @@
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Spectator;
-using osu.Game.Screens.OnlinePlay;
using osu.Game.Tests.Visual.OnlinePlay;
using osu.Game.Tests.Visual.Spectator;
@@ -16,19 +15,16 @@ public class MultiplayerTestSceneDependencies : OnlinePlayTestSceneDependencies,
{
public TestMultiplayerClient MultiplayerClient { get; }
public TestSpectatorClient SpectatorClient { get; }
- public new TestMultiplayerRoomManager RoomManager => (TestMultiplayerRoomManager)base.RoomManager;
public MultiplayerTestSceneDependencies()
{
- MultiplayerClient = new TestMultiplayerClient(RoomManager);
+ MultiplayerClient = new TestMultiplayerClient(RequestsHandler);
SpectatorClient = CreateSpectatorClient();
CacheAs(MultiplayerClient);
CacheAs(SpectatorClient);
}
- protected override IRoomManager CreateRoomManager() => new TestMultiplayerRoomManager(RequestsHandler);
-
protected virtual TestSpectatorClient CreateSpectatorClient() => new TestSpectatorClient();
}
}
diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
index 3abef523cdf8..cc9a82c1ba54 100644
--- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
@@ -10,6 +10,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
+using osu.Game.Beatmaps;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
@@ -17,6 +18,7 @@
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets.Mods;
+using osu.Game.Tests.Visual.OnlinePlay;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -65,15 +67,15 @@ public partial class TestMultiplayerClient : MultiplayerClient
[Resolved]
private IAPIProvider api { get; set; } = null!;
- private readonly TestMultiplayerRoomManager roomManager;
-
private MultiplayerPlaylistItem? currentItem => ServerRoom?.Playlist[currentIndex];
private int currentIndex;
private long lastPlaylistItemId;
- public TestMultiplayerClient(TestMultiplayerRoomManager roomManager)
+ private readonly TestRoomRequestsHandler apiRequestHandler;
+
+ public TestMultiplayerClient(TestRoomRequestsHandler? apiRequestHandler = null)
{
- this.roomManager = roomManager;
+ this.apiRequestHandler = apiRequestHandler ?? new TestRoomRequestsHandler();
}
public void Connect() => isConnected.Value = true;
@@ -206,7 +208,7 @@ public void ChangeUserBeatmapAvailability(int userId, BeatmapAvailability newBea
((IMultiplayerClient)this).UserBeatmapAvailabilityChanged(clone(userId), clone(user.BeatmapAvailability));
}
- protected override async Task JoinRoom(long roomId, string? password = null)
+ protected override async Task JoinRoomInternal(long roomId, string? password = null)
{
if (RoomJoined || ServerAPIRoom != null)
throw new InvalidOperationException("Already joined a room");
@@ -214,7 +216,7 @@ protected override async Task JoinRoom(long roomId, string? pas
roomId = clone(roomId);
password = clone(password);
- ServerAPIRoom = roomManager.ServerSideRooms.Single(r => r.RoomID == roomId);
+ ServerAPIRoom = ServerSideRooms.Single(r => r.RoomID == roomId);
if (password != ServerAPIRoom.Password)
throw new InvalidOperationException("Invalid password.");
@@ -500,6 +502,19 @@ public async Task RemoveUserPlaylistItem(int userId, long playlistItemId)
public override Task RemovePlaylistItem(long playlistItemId) => RemoveUserPlaylistItem(api.LocalUser.Value.OnlineID, clone(playlistItemId));
+ protected override Task CreateRoomInternal(MultiplayerRoom room)
+ {
+ Room apiRoom = new Room(room)
+ {
+ Type = room.Settings.MatchType == MatchType.Playlists
+ ? MatchType.HeadToHead
+ : room.Settings.MatchType
+ };
+
+ AddServerSideRoom(apiRoom, api.LocalUser.Value);
+ return JoinRoomInternal(apiRoom.RoomID!.Value, room.Settings.Password);
+ }
+
private async Task changeMatchType(MatchType type)
{
Debug.Assert(ServerRoom != null);
@@ -692,5 +707,18 @@ public override Task DisconnectInternal()
isConnected.Value = false;
return Task.CompletedTask;
}
+
+ #region API Room Handling
+
+ public IReadOnlyList ServerSideRooms
+ => apiRequestHandler.ServerSideRooms;
+
+ public void AddServerSideRoom(Room room, APIUser host)
+ => apiRequestHandler.AddServerSideRoom(room, host);
+
+ public bool HandleRequest(APIRequest request, APIUser localUser, BeatmapManager beatmapManager)
+ => apiRequestHandler.HandleRequest(request, localUser, beatmapManager);
+
+ #endregion
}
}
diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs
deleted file mode 100644
index b998a638e5b5..000000000000
--- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerRoomManager.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Online.Rooms;
-using osu.Game.Screens.OnlinePlay.Components;
-using osu.Game.Screens.OnlinePlay.Multiplayer;
-using osu.Game.Tests.Visual.OnlinePlay;
-
-namespace osu.Game.Tests.Visual.Multiplayer
-{
- ///
- /// A for use in multiplayer test scenes.
- /// Should generally not be used by itself outside of a .
- ///
- public partial class TestMultiplayerRoomManager : MultiplayerRoomManager
- {
- private readonly TestRoomRequestsHandler requestsHandler;
-
- public TestMultiplayerRoomManager(TestRoomRequestsHandler requestsHandler)
- {
- this.requestsHandler = requestsHandler;
- }
-
- public IReadOnlyList ServerSideRooms => requestsHandler.ServerSideRooms;
-
- public override void CreateRoom(Room room, Action? onSuccess = null, Action? onError = null)
- => base.CreateRoom(room, r => onSuccess?.Invoke(r), onError);
-
- public override void JoinRoom(Room room, string? password = null, Action? onSuccess = null, Action? onError = null)
- => base.JoinRoom(room, password, r => onSuccess?.Invoke(r), onError);
-
- ///
- /// Adds a room to a local "server-side" list that's returned when a is fired.
- ///
- /// The room.
- /// The host.
- public void AddServerSideRoom(Room room, APIUser host) => requestsHandler.AddServerSideRoom(room, host);
- }
-}
diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs
index e2670c9ad890..203922c0576f 100644
--- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs
+++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs
@@ -40,7 +40,7 @@ public OnlinePlayTestSceneDependencies()
RequestsHandler = new TestRoomRequestsHandler();
OngoingOperationTracker = new OngoingOperationTracker();
AvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker();
- RoomManager = CreateRoomManager();
+ RoomManager = new TestRoomManager();
UserLookupCache = new TestUserLookupCache();
BeatmapLookupCache = new BeatmapLookupCache();
@@ -80,7 +80,5 @@ protected void CacheAs(T instance)
if (instance is Drawable drawable)
drawableComponents.Add(drawable);
}
-
- protected virtual IRoomManager CreateRoomManager() => new TestRoomManager();
}
}
diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs
index b1e3eafacc3e..bff275392946 100644
--- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs
+++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomManager.cs
@@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using osu.Framework.Allocation;
using osu.Game.Beatmaps;
+using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
@@ -15,18 +17,19 @@ namespace osu.Game.Tests.Visual.OnlinePlay
///
public partial class TestRoomManager : RoomManager
{
- public Action? JoinRoomRequested;
-
private int currentRoomId;
- public override void JoinRoom(Room room, string? password = null, Action? onSuccess = null, Action? onError = null)
- {
- JoinRoomRequested?.Invoke(room, password);
- base.JoinRoom(room, password, onSuccess, onError);
- }
+ [Resolved]
+ private IAPIProvider api { get; set; } = null!;
+
+ [Resolved]
+ private RulesetStore rulesets { get; set; } = null!;
public void AddRooms(int count, RulesetInfo? ruleset = null, bool withPassword = false, bool withSpotlightRooms = false)
{
+ // Can't reference Osu ruleset project here.
+ ruleset ??= rulesets.GetRuleset(0)!;
+
for (int i = 0; i < count; i++)
{
AddRoom(new Room
@@ -36,12 +39,8 @@ public void AddRooms(int count, RulesetInfo? ruleset = null, bool withPassword =
Duration = TimeSpan.FromSeconds(10),
Category = withSpotlightRooms && i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal,
Password = withPassword ? @"password" : null,
- PlaylistItemStats = ruleset == null
- ? null
- : new Room.RoomPlaylistItemStats { RulesetIDs = [ruleset.OnlineID] },
- Playlist = ruleset == null
- ? Array.Empty()
- : [new PlaylistItem(new BeatmapInfo { Metadata = new BeatmapMetadata() }) { RulesetID = ruleset.OnlineID }]
+ PlaylistItemStats = new Room.RoomPlaylistItemStats { RulesetIDs = [ruleset.OnlineID] },
+ Playlist = [new PlaylistItem(new BeatmapInfo { Metadata = new BeatmapMetadata() }) { RulesetID = ruleset.OnlineID }]
});
}
}
@@ -49,7 +48,11 @@ public void AddRooms(int count, RulesetInfo? ruleset = null, bool withPassword =
public void AddRoom(Room room)
{
room.RoomID = -currentRoomId;
- CreateRoom(room);
+
+ var req = new CreateRoomRequest(room);
+ req.Success += AddOrUpdateRoom;
+ api.Queue(req);
+
currentRoomId++;
}
}