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

Merge pull request #31866 from smoogipoo/remove-roommanager

Remove `RoomManager`, centralise listing management to lounge
This commit is contained in:
Dean Herbert 2025-03-04 15:52:59 +09:00 committed by GitHub
commit 5318c370d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 299 additions and 563 deletions

View File

@ -3,6 +3,7 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@ -19,9 +20,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneLoungeRoomsContainer : OnlinePlayTestScene
{
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private RoomsContainer container = null!;
private BindableList<Room> rooms = null!;
private RoomListing container = null!;
public override void SetUpSteps()
{
@ -29,16 +29,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("create container", () =>
{
rooms = new BindableList<Room>();
Child = new PopoverContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.5f,
Child = container = new RoomsContainer
Child = container = new RoomListing
{
RelativeSizeAxes = Axes.Both,
Rooms = { BindTarget = rooms },
SelectedRoom = { BindTarget = SelectedRoom }
}
};
@ -48,57 +49,58 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestBasicListChanges()
{
AddStep("add rooms", () => RoomManager.AddRooms(5, withSpotlightRooms: true));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(5, withSpotlightRooms: true)));
AddAssert("has 5 rooms", () => container.Rooms.Count == 5);
AddAssert("has 5 rooms", () => container.DrawableRooms.Count == 5);
AddAssert("all spotlights at top", () => container.Rooms
AddAssert("all spotlights at top", () => container.DrawableRooms
.SkipWhile(r => r.Room.Category == RoomCategory.Spotlight)
.All(r => r.Room.Category == RoomCategory.Normal));
AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.First(r => r.RoomID == 0)));
AddAssert("has 4 rooms", () => container.Rooms.Count == 4);
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID != 0));
AddStep("remove first room", () => rooms.RemoveAt(0));
AddAssert("has 4 rooms", () => container.DrawableRooms.Count == 4);
AddAssert("first room removed", () => container.DrawableRooms.All(r => r.Room.RoomID != 0));
AddStep("select first room", () => container.Rooms.First().TriggerClick());
AddAssert("first spotlight selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category == RoomCategory.Spotlight)));
AddStep("select first room", () => container.DrawableRooms.First().TriggerClick());
AddAssert("first spotlight selected", () => checkRoomSelected(rooms.First(r => r.Category == RoomCategory.Spotlight)));
AddStep("remove last room", () => RoomManager.RemoveRoom(RoomManager.Rooms.MinBy(r => r.RoomID)!));
AddAssert("first spotlight still selected", () => checkRoomSelected(RoomManager.Rooms.First(r => r.Category == RoomCategory.Spotlight)));
AddStep("remove last room", () => rooms.RemoveAt(rooms.Count - 1));
AddAssert("first spotlight still selected", () => checkRoomSelected(rooms.First(r => r.Category == RoomCategory.Spotlight)));
AddStep("remove spotlight room", () => RoomManager.RemoveRoom(RoomManager.Rooms.Single(r => r.Category == RoomCategory.Spotlight)));
AddStep("remove spotlight room", () => rooms.RemoveAll(r => r.Category == RoomCategory.Spotlight));
AddAssert("selection vacated", () => checkRoomSelected(null));
}
[Test]
public void TestKeyboardNavigation()
{
AddStep("add rooms", () => RoomManager.AddRooms(3));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(3)));
AddAssert("no selection", () => checkRoomSelected(null));
press(Key.Down);
AddAssert("first room selected", () => checkRoomSelected(RoomManager.Rooms.First()));
AddAssert("first room selected", () => checkRoomSelected(container.DrawableRooms.First().Room));
press(Key.Up);
AddAssert("first room selected", () => checkRoomSelected(RoomManager.Rooms.First()));
AddAssert("first room selected", () => checkRoomSelected(container.DrawableRooms.First().Room));
press(Key.Down);
press(Key.Down);
AddAssert("last room selected", () => checkRoomSelected(RoomManager.Rooms.Last()));
AddAssert("last room selected", () => checkRoomSelected(container.DrawableRooms.Last().Room));
}
[Test]
public void TestKeyboardNavigationAfterOrderChange()
{
AddStep("add rooms", () => RoomManager.AddRooms(3));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(3)));
AddStep("reorder rooms", () =>
{
var room = RoomManager.Rooms[1];
var room = rooms[1];
rooms.Remove(room);
RoomManager.RemoveRoom(room);
RoomManager.AddOrUpdateRoom(room);
room.RoomID += 3;
rooms.Add(room);
});
AddAssert("no selection", () => checkRoomSelected(null));
@ -116,12 +118,12 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestClickDeselection()
{
AddStep("add room", () => RoomManager.AddRooms(1));
AddStep("add room", () => rooms.AddRange(GenerateRooms(1)));
AddAssert("no selection", () => checkRoomSelected(null));
press(Key.Down);
AddAssert("first room selected", () => checkRoomSelected(RoomManager.Rooms.First()));
AddAssert("first room selected", () => checkRoomSelected(container.DrawableRooms.First().Room));
AddStep("click away", () => InputManager.Click(MouseButton.Left));
AddAssert("no selection", () => checkRoomSelected(null));
@ -135,34 +137,34 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestStringFiltering()
{
AddStep("add rooms", () => RoomManager.AddRooms(4));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(4)));
AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4);
AddUntilStep("4 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 4);
AddStep("filter one room", () => container.Filter.Value = new FilterCriteria { SearchString = "1" });
AddStep("filter one room", () => container.Filter.Value = new FilterCriteria { SearchString = rooms.First().Name });
AddUntilStep("1 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 1);
AddUntilStep("1 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 1);
AddStep("remove filter", () => container.Filter.Value = null);
AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4);
AddUntilStep("4 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 4);
}
[Test]
public void TestRulesetFiltering()
{
AddStep("add rooms", () => RoomManager.AddRooms(2, new OsuRuleset().RulesetInfo));
AddStep("add rooms", () => RoomManager.AddRooms(3, new CatchRuleset().RulesetInfo));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(2, new OsuRuleset().RulesetInfo)));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(3, new CatchRuleset().RulesetInfo)));
// Todo: What even is this case...?
AddStep("set empty filter criteria", () => container.Filter.Value = new FilterCriteria());
AddUntilStep("5 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 5);
AddUntilStep("5 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 5);
AddStep("filter osu! rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo });
AddUntilStep("2 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 2);
AddUntilStep("2 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 2);
AddStep("filter catch rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo });
AddUntilStep("3 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 3);
AddUntilStep("3 rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 3);
}
[Test]
@ -170,27 +172,27 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("add rooms", () =>
{
RoomManager.AddRooms(1, withPassword: true);
RoomManager.AddRooms(1, withPassword: false);
rooms.AddRange(GenerateRooms(1, withPassword: true));
rooms.AddRange(GenerateRooms(1, withPassword: false));
});
AddStep("apply default filter", () => container.Filter.SetDefault());
AddUntilStep("both rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 2);
AddUntilStep("both rooms visible", () => container.DrawableRooms.Count(r => r.IsPresent) == 2);
AddStep("filter public rooms", () => container.Filter.Value = new FilterCriteria { Permissions = RoomPermissionsFilter.Public });
AddUntilStep("private room hidden", () => container.Rooms.All(r => !r.Room.HasPassword));
AddUntilStep("private room hidden", () => container.DrawableRooms.All(r => !r.Room.HasPassword));
AddStep("filter private rooms", () => container.Filter.Value = new FilterCriteria { Permissions = RoomPermissionsFilter.Private });
AddUntilStep("public room hidden", () => container.Rooms.All(r => r.Room.HasPassword));
AddUntilStep("public room hidden", () => container.DrawableRooms.All(r => r.Room.HasPassword));
}
[Test]
public void TestPasswordProtectedRooms()
{
AddStep("add rooms", () => RoomManager.AddRooms(3, withPassword: true));
AddStep("add rooms", () => rooms.AddRange(GenerateRooms(3, withPassword: true)));
}
private bool checkRoomSelected(Room? room) => SelectedRoom.Value == room;

View File

@ -33,7 +33,6 @@ using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Match;
@ -806,7 +805,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddUntilStep("wait for room", () => this.ChildrenOfType<DrawableRoom>().Any());
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("disable polling", () => this.ChildrenOfType<ListingPollingComponent>().Single().TimeBetweenPolls.Value = 0);
AddStep("disable polling", () => this.ChildrenOfType<LoungeListingPoller>().Single().TimeBetweenPolls.Value = 0);
AddStep("change server-side settings", () =>
{
multiplayerClient.ServerSideRooms[0].Name = "New name";

View File

@ -8,8 +8,8 @@ using osu.Framework.Graphics.UserInterface;
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;
@ -18,11 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
public partial class TestSceneMultiplayerLoungeSubScreen : MultiplayerTestScene
{
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private LoungeSubScreen loungeScreen = null!;
private RoomsContainer roomsContainer => loungeScreen.ChildrenOfType<RoomsContainer>().First();
private MultiplayerLoungeSubScreen loungeScreen = null!;
public TestSceneMultiplayerLoungeSubScreen()
: base(false)
@ -40,7 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestJoinRoomWithoutPassword()
{
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: false));
createRooms(GenerateRooms(1, withPassword: false));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("join room", () => InputManager.Key(Key.Enter));
@ -50,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestPopoverHidesOnBackButton()
{
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
createRooms(GenerateRooms(1, withPassword: true));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
@ -70,7 +66,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Test]
public void TestPopoverHidesOnLeavingScreen()
{
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
createRooms(GenerateRooms(1, withPassword: true));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
@ -86,7 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
DrawableLoungeRoom.PasswordEntryPopover? passwordEntryPopover = null;
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
createRooms(GenerateRooms(1, withPassword: true));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
@ -105,7 +101,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
DrawableLoungeRoom.PasswordEntryPopover? passwordEntryPopover = null;
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
createRooms(GenerateRooms(1, withPassword: true));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
@ -124,7 +120,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
DrawableLoungeRoom.PasswordEntryPopover? passwordEntryPopover = null;
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
createRooms(GenerateRooms(1, withPassword: true));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
@ -139,7 +135,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
DrawableLoungeRoom.PasswordEntryPopover? passwordEntryPopover = null;
AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true));
createRooms(GenerateRooms(1, withPassword: true));
AddStep("select room", () => InputManager.Key(Key.Down));
AddStep("attempt join room", () => InputManager.Key(Key.Enter));
AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType<DrawableLoungeRoom.PasswordEntryPopover>().FirstOrDefault()) != null);
@ -149,6 +145,17 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("room joined", () => MultiplayerClient.RoomJoined);
}
private void createRooms(params Room[] rooms)
{
AddStep("create rooms", () =>
{
foreach (var room in rooms)
API.Queue(new CreateRoomRequest(room));
});
AddStep("refresh lounge", () => loungeScreen.RefreshRooms());
}
protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new MultiplayerTestSceneDependencies();
}
}

View File

@ -3,7 +3,6 @@
using System.Linq;
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Graphics.Containers;
@ -17,26 +16,22 @@ namespace osu.Game.Tests.Visual.Playlists
{
public partial class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene
{
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private TestLoungeSubScreen loungeScreen = null!;
private PlaylistsLoungeSubScreen loungeScreen = null!;
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("push screen", () => LoadScreen(loungeScreen = new TestLoungeSubScreen()));
AddStep("push screen", () => LoadScreen(loungeScreen = new PlaylistsLoungeSubScreen()));
AddUntilStep("wait for present", () => loungeScreen.IsCurrentScreen());
}
private RoomsContainer roomsContainer => loungeScreen.ChildrenOfType<RoomsContainer>().First();
private RoomListing roomListing => loungeScreen.ChildrenOfType<RoomListing>().First();
[Test]
public void TestManyRooms()
{
AddStep("add rooms", () => RoomManager.AddRooms(500));
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 500);
createRooms(GenerateRooms(500));
}
[Test]
@ -44,60 +39,41 @@ namespace osu.Game.Tests.Visual.Playlists
{
AddStep("reset mouse", () => InputManager.ReleaseButton(MouseButton.Left));
AddStep("add rooms", () => RoomManager.AddRooms(30));
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30);
createRooms(GenerateRooms(30));
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
AddStep("move mouse to third room", () => InputManager.MoveMouseTo(roomsContainer.Rooms[2]));
AddStep("move mouse to third room", () => InputManager.MoveMouseTo(roomListing.DrawableRooms[2]));
AddStep("hold down", () => InputManager.PressButton(MouseButton.Left));
AddStep("drag to top", () => InputManager.MoveMouseTo(roomsContainer.Rooms[0]));
AddStep("drag to top", () => InputManager.MoveMouseTo(roomListing.DrawableRooms[0]));
AddAssert("first and second room masked", ()
=> !checkRoomVisible(roomsContainer.Rooms[0]) &&
!checkRoomVisible(roomsContainer.Rooms[1]));
=> !checkRoomVisible(roomListing.DrawableRooms[0]) &&
!checkRoomVisible(roomListing.DrawableRooms[1]));
}
[Test]
public void TestScrollSelectedIntoView()
{
AddStep("add rooms", () => RoomManager.AddRooms(30));
AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30);
createRooms(GenerateRooms(30));
AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0]));
AddStep("select last room", () => roomListing.DrawableRooms[^1].TriggerClick());
AddStep("select last room", () => roomsContainer.Rooms[^1].TriggerClick());
AddUntilStep("first room is masked", () => !checkRoomVisible(roomsContainer.Rooms[0]));
AddUntilStep("last room is not masked", () => checkRoomVisible(roomsContainer.Rooms[^1]));
}
[Test]
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);
AddStep("select room", () => roomsContainer.Rooms[0].TriggerClick());
AddAssert("selected room is non-null", () => loungeScreen.SelectedRoom.Value != null);
AddStep("enter room", () => roomsContainer.Rooms[0].TriggerClick());
AddUntilStep("wait for match load", () => Stack.CurrentScreen is PlaylistsRoomSubScreen);
AddAssert("selected room is non-null", () => loungeScreen.SelectedRoom.Value != null);
AddAssert("selected room is disabled", () => loungeScreen.SelectedRoom.Disabled);
AddUntilStep("first room is masked", () => !checkRoomVisible(roomListing.DrawableRooms[0]));
AddUntilStep("last room is not masked", () => checkRoomVisible(roomListing.DrawableRooms[^1]));
}
private bool checkRoomVisible(DrawableRoom room) =>
loungeScreen.ChildrenOfType<OsuScrollContainer>().First().ScreenSpaceDrawQuad
.Contains(room.ScreenSpaceDrawQuad.Centre);
private partial class TestLoungeSubScreen : PlaylistsLoungeSubScreen
private void createRooms(params Room[] rooms)
{
public new Bindable<Room?> SelectedRoom => base.SelectedRoom;
AddStep("create rooms", () =>
{
foreach (var room in rooms)
API.Queue(new CreateRoomRequest(room));
});
AddStep("refresh lounge", () => loungeScreen.RefreshRooms());
}
}
}

View File

@ -17,8 +17,6 @@ namespace osu.Game.Tests.Visual.Playlists
{
public partial class TestScenePlaylistsMatchSettingsOverlay : OnlinePlayTestScene
{
protected new TestRoomManager RoomManager => (TestRoomManager)base.RoomManager;
private TestRoomSettings settings = null!;
private Func<Room, string?>? handleRequest;

View File

@ -1,77 +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.
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
namespace osu.Game.Screens.OnlinePlay.Components
{
/// <summary>
/// A <see cref="RoomPollingComponent"/> that polls for the lounge listing.
/// </summary>
public partial class ListingPollingComponent : RoomPollingComponent
{
public IBindable<bool> InitialRoomsReceived => initialRoomsReceived;
private readonly Bindable<bool> initialRoomsReceived = new Bindable<bool>();
public readonly Bindable<FilterCriteria?> Filter = new Bindable<FilterCriteria?>();
[BackgroundDependencyLoader]
private void load()
{
Filter.BindValueChanged(_ =>
{
RoomManager.ClearRooms();
initialRoomsReceived.Value = false;
if (IsLoaded)
PollImmediately();
});
}
private GetRoomsRequest? lastPollRequest;
protected override Task Poll()
{
if (!API.IsLoggedIn)
return base.Poll();
if (Filter.Value == null)
return base.Poll();
var tcs = new TaskCompletionSource<bool>();
lastPollRequest?.Cancel();
var req = new GetRoomsRequest(Filter.Value);
req.Success += result =>
{
result = result.Where(r => r.Category != RoomCategory.DailyChallenge).ToList();
foreach (var existing in RoomManager.Rooms.ToArray())
{
if (result.All(r => r.RoomID != existing.RoomID))
RoomManager.RemoveRoom(existing);
}
foreach (var incoming in result)
RoomManager.AddOrUpdateRoom(incoming);
initialRoomsReceived.Value = true;
tcs.SetResult(true);
};
req.Failure += _ => tcs.SetResult(false);
API.Queue(req);
lastPollRequest = req;
return tcs.Task;
}
}
}

View File

@ -1,82 +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.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Development;
using osu.Framework.Graphics;
using osu.Framework.Logging;
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;
private readonly BindableList<Room> rooms = new BindableList<Room>();
public IBindableList<Room> Rooms => rooms;
public RoomManager()
{
RelativeSizeAxes = Axes.Both;
}
private readonly HashSet<long> ignoredRooms = new HashSet<long>();
public void AddOrUpdateRoom(Room room)
{
Debug.Assert(ThreadSafety.IsUpdateThread);
Debug.Assert(room.RoomID != null);
if (ignoredRooms.Contains(room.RoomID.Value))
return;
try
{
var existing = rooms.FirstOrDefault(e => e.RoomID == room.RoomID);
if (existing == null)
rooms.Add(room);
else
existing.CopyFrom(room);
}
catch (Exception ex)
{
Logger.Error(ex, $"Failed to update room: {room.Name}.");
ignoredRooms.Add(room.RoomID.Value);
rooms.Remove(room);
}
notifyRoomsUpdated();
}
public void RemoveRoom(Room room)
{
Debug.Assert(ThreadSafety.IsUpdateThread);
rooms.Remove(room);
notifyRoomsUpdated();
}
public void ClearRooms()
{
Debug.Assert(ThreadSafety.IsUpdateThread);
rooms.Clear();
notifyRoomsUpdated();
}
private void notifyRoomsUpdated()
{
Scheduler.AddOnce(invokeRoomsUpdated);
void invokeRoomsUpdated() => RoomsUpdated?.Invoke();
}
}
}

View File

@ -1,18 +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.
using osu.Framework.Allocation;
using osu.Game.Online;
using osu.Game.Online.API;
namespace osu.Game.Screens.OnlinePlay.Components
{
public abstract partial class RoomPollingComponent : PollingComponent
{
[Resolved]
protected IAPIProvider API { get; private set; } = null!;
[Resolved]
protected IRoomManager RoomManager { get; private set; } = null!;
}
}

View File

@ -204,7 +204,7 @@ namespace osu.Game.Screens.OnlinePlay
ScrollContainer.ScrollIntoView(drawableItem);
}
#region Key selection logic (shared with BeatmapCarousel and RoomsContainer)
#region Key selection logic (shared with BeatmapCarousel and RoomListing)
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
{

View File

@ -1,42 +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.
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online.Rooms;
namespace osu.Game.Screens.OnlinePlay
{
[Cached(typeof(IRoomManager))]
public interface IRoomManager
{
/// <summary>
/// Invoked when the <see cref="Room"/>s have been updated.
/// </summary>
event Action RoomsUpdated;
/// <summary>
/// All the active <see cref="Room"/>s.
/// </summary>
IBindableList<Room> Rooms { get; }
/// <summary>
/// Adds a <see cref="Room"/> to this <see cref="IRoomManager"/>.
/// If already existing, the local room will be updated with the given one.
/// </summary>
/// <param name="room">The incoming <see cref="Room"/>.</param>
void AddOrUpdateRoom(Room room);
/// <summary>
/// Removes a <see cref="Room"/> from this <see cref="IRoomManager"/>.
/// </summary>
/// <param name="room">The <see cref="Room"/> to remove.</param>
void RemoveRoom(Room room);
/// <summary>
/// Removes all <see cref="Room"/>s from this <see cref="IRoomManager"/>.
/// </summary>
void ClearRooms();
}
}

View File

@ -7,14 +7,13 @@ using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Input.Bindings;
using osu.Game.Online.Rooms;
@ -22,31 +21,41 @@ using osuTK;
namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
public partial class RoomsContainer : CompositeDrawable, IKeyBindingHandler<GlobalAction>
public partial class RoomListing : CompositeDrawable, IKeyBindingHandler<GlobalAction>
{
public readonly Bindable<Room?> SelectedRoom = new Bindable<Room?>();
/// <summary>
/// Rooms which should be displayed. Should be managed externally.
/// </summary>
public readonly BindableList<Room> Rooms = new BindableList<Room>();
/// <summary>
/// The current filter criteria. Should be managed externally.
/// </summary>
public readonly Bindable<FilterCriteria?> Filter = new Bindable<FilterCriteria?>();
public IReadOnlyList<DrawableRoom> Rooms => roomFlow.FlowingChildren.Cast<DrawableRoom>().ToArray();
/// <summary>
/// The currently user-selected room.
/// </summary>
public IBindable<Room?> SelectedRoom => selectedRoom;
private readonly IBindableList<Room> rooms = new BindableList<Room>();
private readonly Bindable<Room?> selectedRoom = new Bindable<Room?>();
public IReadOnlyList<DrawableRoom> DrawableRooms => roomFlow.FlowingChildren.Cast<DrawableRoom>().ToArray();
private readonly ScrollContainer<Drawable> scroll;
private readonly FillFlowContainer<DrawableLoungeRoom> roomFlow;
[Resolved]
private IRoomManager roomManager { get; set; } = null!;
// handle deselection
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
public RoomsContainer()
public RoomListing()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
// account for the fact we are in a scroll container and want a bit of spacing from the scroll bar.
Padding = new MarginPadding { Right = 5 };
InternalChild = new OsuContextMenuContainer
InternalChild = scroll = new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
ScrollbarOverlapsContent = false,
Padding = new MarginPadding { Right = 5 },
Child = new OsuContextMenuContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
@ -57,16 +66,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
Direction = FillDirection.Vertical,
Spacing = new Vector2(10),
}
}
};
}
protected override void LoadComplete()
{
rooms.CollectionChanged += roomsChanged;
roomManager.RoomsUpdated += updateSorting;
rooms.BindTo(roomManager.Rooms);
SelectedRoom.BindValueChanged(onSelectedRoomChanged, true);
Rooms.BindCollectionChanged(roomsChanged, true);
Filter.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
}
@ -128,6 +135,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
}
}
private void onSelectedRoomChanged(ValueChangedEvent<Room?> room)
{
// scroll selected room into view on selection.
var drawable = DrawableRooms.FirstOrDefault(r => r.Room == room.NewValue);
if (drawable != null)
scroll.ScrollIntoView(drawable);
}
private void roomsChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
@ -155,7 +170,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private void addRooms(IEnumerable<Room> rooms)
{
foreach (var room in rooms)
roomFlow.Add(new DrawableLoungeRoom(room) { SelectedRoom = SelectedRoom });
{
var drawableRoom = new DrawableLoungeRoom(room) { SelectedRoom = selectedRoom };
roomFlow.Add(drawableRoom);
// Always show spotlight playlists at the top of the listing.
roomFlow.SetLayoutPosition(drawableRoom, room.Category > RoomCategory.Normal ? float.MinValue : -(room.RoomID ?? 0));
}
applyFilterCriteria(Filter.Value);
}
@ -168,7 +190,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
// selection may have a lease due to being in a sub screen.
if (SelectedRoom.Value == r && !SelectedRoom.Disabled)
SelectedRoom.Value = null;
selectedRoom.Value = null;
}
}
@ -178,24 +200,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
// selection may have a lease due to being in a sub screen.
if (!SelectedRoom.Disabled)
SelectedRoom.Value = null;
}
private void updateSorting()
{
foreach (var room in roomFlow)
{
roomFlow.SetLayoutPosition(room, room.Room.Category > RoomCategory.Normal
// Always show spotlight playlists at the top of the listing.
? float.MinValue
: -(room.Room.RoomID ?? 0));
}
selectedRoom.Value = null;
}
protected override bool OnClick(ClickEvent e)
{
if (!SelectedRoom.Disabled)
SelectedRoom.Value = null;
selectedRoom.Value = null;
return base.OnClick(e);
}
@ -226,7 +237,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
if (SelectedRoom.Disabled)
return;
var visibleRooms = Rooms.AsEnumerable().Where(r => r.IsPresent);
var visibleRooms = DrawableRooms.AsEnumerable().Where(r => r.IsPresent);
Room? room;
@ -242,17 +253,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
// we already have a valid selection only change selection if we still have a room to switch to.
if (room != null)
SelectedRoom.Value = room;
selectedRoom.Value = room;
}
#endregion
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (roomManager.IsNotNull())
roomManager.RoomsUpdated -= updateSorting;
}
}
}

View File

@ -0,0 +1,57 @@
// 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.
using System;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
namespace osu.Game.Screens.OnlinePlay.Lounge
{
/// <summary>
/// Polls for rooms for the main lounge listing.
/// </summary>
public partial class LoungeListingPoller : PollingComponent
{
[Resolved]
private IAPIProvider api { get; set; } = null!;
public required Action<Room[]> RoomsReceived { get; init; }
public readonly IBindable<FilterCriteria?> Filter = new Bindable<FilterCriteria?>();
private GetRoomsRequest? lastPollRequest;
protected override Task Poll()
{
if (!api.IsLoggedIn)
return base.Poll();
if (Filter.Value == null)
return base.Poll();
lastPollRequest?.Cancel();
var tcs = new TaskCompletionSource<bool>();
var req = new GetRoomsRequest(Filter.Value);
req.Success += result =>
{
RoomsReceived(result.Where(r => r.Category != RoomCategory.DailyChallenge).ToArray());
tcs.SetResult(true);
};
req.Failure += _ => tcs.SetResult(false);
api.Queue(req);
lastPollRequest = req;
return tcs.Task;
}
}
}

View File

@ -17,14 +17,12 @@ using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Match;
using osu.Game.Users;
@ -40,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen
{
SelectedRoom = { BindTarget = SelectedRoom }
SelectedRoom = { BindTarget = roomListing.SelectedRoom }
};
protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby();
@ -52,10 +50,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
AutoSizeAxes = Axes.Both
};
protected ListingPollingComponent ListingPollingComponent { get; private set; } = null!;
protected readonly Bindable<Room?> SelectedRoom = new Bindable<Room?>();
[Resolved]
private MusicController music { get; set; } = null!;
@ -74,15 +68,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
[Resolved]
protected OsuConfigManager Config { get; private set; } = null!;
private IDisposable? joiningRoomOperation { get; set; }
private LeasedBindable<Room?>? selectionLease;
private IDisposable? joiningRoomOperation;
private readonly Bindable<FilterCriteria?> filter = new Bindable<FilterCriteria?>();
private readonly Bindable<bool> hasListingResults = new Bindable<bool>();
private readonly IBindable<bool> operationInProgress = new Bindable<bool>();
private readonly IBindable<bool> isIdle = new BindableBool();
private RoomListing roomListing = null!;
private LoungeListingPoller listingPoller = null!;
private PopoverContainer popoverContainer = null!;
private LoadingLayer loadingLayer = null!;
private RoomsContainer roomsContainer = null!;
private SearchTextBox searchTextBox = null!;
protected Dropdown<RoomModeFilter> StatusDropdown { get; private set; } = null!;
@ -95,11 +90,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
if (idleTracker != null)
isIdle.BindTo(idleTracker.IsIdle);
OsuScrollContainer scrollContainer;
InternalChildren = new Drawable[]
{
ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter),
listingPoller = new LoungeListingPoller
{
RoomsReceived = onListingReceived,
Filter = { BindTarget = filter }
},
popoverContainer = new PopoverContainer
{
Name = @"Rooms area",
@ -109,17 +106,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
Horizontal = WaveOverlayContainer.WIDTH_PADDING,
Top = Header.HEIGHT + controls_area_height + 20,
},
Child = scrollContainer = new OsuScrollContainer
Child = roomListing = new RoomListing
{
RelativeSizeAxes = Axes.Both,
ScrollbarOverlapsContent = false,
Child = roomsContainer = new RoomsContainer
{
Filter = { BindTarget = filter },
SelectedRoom = { BindTarget = SelectedRoom }
}
},
},
loadingLayer = new LoadingLayer(true),
new FillFlowContainer
{
@ -173,14 +165,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
},
},
};
// scroll selected room into view on selection.
SelectedRoom.BindValueChanged(val =>
{
var drawable = roomsContainer.Rooms.FirstOrDefault(r => r.Room == val.NewValue);
if (drawable != null)
scrollContainer.ScrollIntoView(drawable);
});
}
protected override void LoadComplete()
@ -189,7 +173,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced());
ruleset.BindValueChanged(_ => UpdateFilter());
isIdle.BindValueChanged(_ => updatePollingRate(this.IsCurrentScreen()), true);
if (ongoingOperationTracker != null)
@ -198,11 +181,38 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
operationInProgress.BindValueChanged(_ => updateLoadingLayer());
}
ListingPollingComponent.InitialRoomsReceived.BindValueChanged(_ => updateLoadingLayer(), true);
hasListingResults.BindValueChanged(_ => updateLoadingLayer());
filter.BindValueChanged(_ =>
{
roomListing.Rooms.Clear();
hasListingResults.Value = false;
listingPoller.PollImmediately();
});
updateFilter();
}
private void onListingReceived(Room[] result)
{
Dictionary<long, Room> localRoomsById = roomListing.Rooms.ToDictionary(r => r.RoomID!.Value);
Dictionary<long, Room> resultRoomsById = result.ToDictionary(r => r.RoomID!.Value);
// Remove all local rooms no longer in the result set.
roomListing.Rooms.RemoveAll(r => !resultRoomsById.ContainsKey(r.RoomID!.Value));
// Add or update local rooms with the result set.
foreach (var r in result)
{
if (localRoomsById.TryGetValue(r.RoomID!.Value, out Room? existingRoom))
existingRoom.CopyFrom(r);
else
roomListing.Rooms.Add(r);
}
hasListingResults.Value = true;
}
#region Filtering
public void UpdateFilter() => Scheduler.AddOnce(updateFilter);
@ -253,20 +263,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
{
base.OnResuming(e);
Debug.Assert(selectionLease != null);
selectionLease.Return();
selectionLease = null;
if (SelectedRoom.Value?.RoomID == null)
SelectedRoom.Value = new Room();
music.EnsurePlayingSomething();
onReturning();
// Poll for any newly-created rooms (including potentially the user's own).
ListingPollingComponent.PollImmediately();
listingPoller.PollImmediately();
}
public override bool OnExiting(ScreenExitEvent e)
@ -375,20 +377,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
OpenNewRoom(room ?? CreateNewRoom());
});
protected virtual void OpenNewRoom(Room room)
{
selectionLease = SelectedRoom.BeginLease(false);
Debug.Assert(selectionLease != null);
selectionLease.Value = room;
protected virtual void OpenNewRoom(Room room) => this.Push(CreateRoomSubScreen(room));
this.Push(CreateRoomSubScreen(room));
}
public void RefreshRooms() => ListingPollingComponent.PollImmediately();
public void RefreshRooms() => listingPoller.PollImmediately();
private void updateLoadingLayer()
{
if (operationInProgress.Value || !ListingPollingComponent.InitialRoomsReceived.Value)
if (operationInProgress.Value || !hasListingResults.Value)
loadingLayer.Show();
else
loadingLayer.Hide();
@ -397,11 +392,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
private void updatePollingRate(bool isCurrentScreen)
{
if (!isCurrentScreen)
ListingPollingComponent.TimeBetweenPolls.Value = 0;
listingPoller.TimeBetweenPolls.Value = 0;
else
ListingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000;
listingPoller.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000;
Logger.Log($"Polling adjusted (listing: {ListingPollingComponent.TimeBetweenPolls.Value})");
Logger.Log($"Polling adjusted (listing: {listingPoller.TimeBetweenPolls.Value})");
}
protected abstract OsuButton CreateNewRoomButton();
@ -413,7 +408,5 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
protected abstract Room CreateNewRoom();
protected abstract RoomSubScreen CreateRoomSubScreen(Room room);
protected abstract ListingPollingComponent CreatePollingComponent();
}
}

View File

@ -3,9 +3,7 @@
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.Graphics;
@ -15,7 +13,6 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Match;
@ -79,8 +76,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room);
protected override ListingPollingComponent CreatePollingComponent() => new MultiplayerListingPollingComponent();
protected override void JoinInternal(Room room, string? password, Action<Room> onSuccess, Action<string> onFailure)
{
client.JoinRoom(room, password).ContinueWith(result =>
@ -112,37 +107,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
base.OpenNewRoom(room);
}
private partial class MultiplayerListingPollingComponent : ListingPollingComponent
{
[Resolved]
private MultiplayerClient client { get; set; } = null!;
private readonly IBindable<bool> isConnected = new Bindable<bool>();
[BackgroundDependencyLoader]
private void load()
{
isConnected.BindTo(client.IsConnected);
isConnected.BindValueChanged(_ => Scheduler.AddOnce(poll), true);
}
private void poll()
{
if (isConnected.Value && IsLoaded)
PollImmediately();
}
protected override Task Poll()
{
if (!isConnected.Value)
return Task.CompletedTask;
if (client.Room != null)
return Task.CompletedTask;
return base.Poll();
}
}
}
}

View File

@ -11,7 +11,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Users;
@ -39,9 +38,6 @@ namespace osu.Game.Screens.OnlinePlay
[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!;
@ -65,7 +61,6 @@ namespace osu.Game.Screens.OnlinePlay
{
screenStack,
new Header(ScreenTitle, screenStack),
roomManager,
ongoingOperationTracker,
}
};

View File

@ -13,7 +13,6 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.Rooms;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Screens.OnlinePlay.Lounge;
using osu.Game.Screens.OnlinePlay.Lounge.Components;
using osu.Game.Screens.OnlinePlay.Match;
@ -98,8 +97,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room);
protected override ListingPollingComponent CreatePollingComponent() => new ListingPollingComponent();
private enum PlaylistsCategory
{
Any,

View File

@ -44,7 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private IdleTracker? idleTracker { get; set; }
private MatchLeaderboard leaderboard = null!;
private SelectionPollingComponent selectionPollingComponent = null!;
private PlaylistsRoomUpdater roomUpdater = null!;
private FillFlowContainer progressSection = null!;
private DrawableRoomPlaylist drawablePlaylist = null!;
@ -64,7 +64,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
if (idleTracker != null)
isIdle.BindTo(idleTracker.IsIdle);
AddInternal(selectionPollingComponent = new SelectionPollingComponent(Room));
AddInternal(roomUpdater = new PlaylistsRoomUpdater(Room));
}
protected override void LoadComplete()
@ -330,8 +330,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void updatePollingRate()
{
selectionPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 30000 : 5000;
Logger.Log($"Polling adjusted (selection: {selectionPollingComponent.TimeBetweenPolls.Value})");
roomUpdater.TimeBetweenPolls.Value = isIdle.Value ? 30000 : 5000;
Logger.Log($"Polling adjusted (selection: {roomUpdater.TimeBetweenPolls.Value})");
}
private void closePlaylist()

View File

@ -2,18 +2,24 @@
// See the LICENCE file in the repository root for full licence text.
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Game.Online;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
namespace osu.Game.Screens.OnlinePlay.Components
namespace osu.Game.Screens.OnlinePlay.Playlists
{
/// <summary>
/// A <see cref="RoomPollingComponent"/> that polls for the currently-selected room.
/// A <see cref="PollingComponent"/> that polls for and updates a room.
/// </summary>
public partial class SelectionPollingComponent : RoomPollingComponent
public partial class PlaylistsRoomUpdater : PollingComponent
{
[Resolved]
private IAPIProvider api { get; set; } = null!;
private readonly Room room;
public SelectionPollingComponent(Room room)
public PlaylistsRoomUpdater(Room room)
{
this.room = room;
}
@ -22,27 +28,26 @@ namespace osu.Game.Screens.OnlinePlay.Components
protected override Task Poll()
{
if (!API.IsLoggedIn)
if (!api.IsLoggedIn)
return base.Poll();
if (room.RoomID == null)
return base.Poll();
var tcs = new TaskCompletionSource<bool>();
lastPollRequest?.Cancel();
var tcs = new TaskCompletionSource<bool>();
var req = new GetRoomRequest(room.RoomID.Value);
req.Success += result =>
{
RoomManager.AddOrUpdateRoom(result);
room.CopyFrom(result);
tcs.SetResult(true);
};
req.Failure += _ => tcs.SetResult(false);
API.Queue(req);
api.Queue(req);
lastPollRequest = req;

View File

@ -18,11 +18,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// </summary>
Bindable<Room?> SelectedRoom { get; }
/// <summary>
/// The cached <see cref="IRoomManager"/>
/// </summary>
IRoomManager RoomManager { get; }
/// <summary>
/// The cached <see cref="OngoingOperationTracker"/>.
/// </summary>

View File

@ -10,7 +10,9 @@ using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Screens.OnlinePlay;
namespace osu.Game.Tests.Visual.OnlinePlay
@ -21,7 +23,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
public abstract partial class OnlinePlayTestScene : ScreenTestScene, IOnlinePlayTestSceneDependencies
{
public Bindable<Room?> SelectedRoom => OnlinePlayDependencies.SelectedRoom;
public IRoomManager RoomManager => OnlinePlayDependencies.RoomManager;
public OngoingOperationTracker OngoingOperationTracker => OnlinePlayDependencies.OngoingOperationTracker;
public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker => OnlinePlayDependencies.AvailabilityTracker;
public TestUserLookupCache UserLookupCache => OnlinePlayDependencies.UserLookupCache;
@ -34,9 +35,13 @@ namespace osu.Game.Tests.Visual.OnlinePlay
protected override Container<Drawable> Content => content;
[Resolved]
private RulesetStore rulesets { get; set; } = null!;
private readonly Container content;
private readonly Container drawableDependenciesContainer;
private DelegatedDependencyContainer dependencies = null!;
private int currentRoomId;
protected OnlinePlayTestScene()
{
@ -93,6 +98,31 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// </remarks>
protected virtual OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new OnlinePlayTestSceneDependencies();
protected Room[] GenerateRooms(int count, RulesetInfo? ruleset = null, bool withPassword = false, bool withSpotlightRooms = false)
{
Room[] rooms = new Room[count];
// Can't reference Osu ruleset project here.
ruleset ??= rulesets.GetRuleset(0)!;
for (int i = 0; i < count; i++)
{
rooms[i] = new Room
{
RoomID = currentRoomId++,
Name = $@"Room {currentRoomId}",
Host = new APIUser { Username = @"Host" },
Duration = TimeSpan.FromSeconds(10),
Category = withSpotlightRooms && i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal,
Password = withPassword ? @"password" : null,
PlaylistItemStats = new Room.RoomPlaylistItemStats { RulesetIDs = [ruleset.OnlineID] },
Playlist = [new PlaylistItem(new BeatmapInfo { Metadata = new BeatmapMetadata() }) { RulesetID = ruleset.OnlineID }]
};
}
return rooms;
}
/// <summary>
/// A <see cref="IReadOnlyDependencyContainer"/> providing a mutable lookup source for online play dependencies.
/// </summary>

View File

@ -19,7 +19,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
public class OnlinePlayTestSceneDependencies : IReadOnlyDependencyContainer, IOnlinePlayTestSceneDependencies
{
public Bindable<Room?> SelectedRoom { get; }
public IRoomManager RoomManager { get; }
public OngoingOperationTracker OngoingOperationTracker { get; }
public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker { get; }
public TestRoomRequestsHandler RequestsHandler { get; }
@ -40,7 +39,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
RequestsHandler = new TestRoomRequestsHandler();
OngoingOperationTracker = new OngoingOperationTracker();
AvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker();
RoomManager = new TestRoomManager();
UserLookupCache = new TestUserLookupCache();
BeatmapLookupCache = new BeatmapLookupCache();
@ -48,7 +46,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
CacheAs(RequestsHandler);
CacheAs(SelectedRoom);
CacheAs(RoomManager);
CacheAs(OngoingOperationTracker);
CacheAs(AvailabilityTracker);
CacheAs(new OverlayColourProvider(OverlayColourScheme.Plum));

View File

@ -1,59 +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.
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;
using osu.Game.Screens.OnlinePlay.Components;
namespace osu.Game.Tests.Visual.OnlinePlay
{
/// <summary>
/// A very simple <see cref="RoomManager"/> for use in online play test scenes.
/// </summary>
public partial class TestRoomManager : RoomManager
{
private int currentRoomId;
[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
{
Name = $@"Room {currentRoomId}",
Host = new APIUser { Username = @"Host" },
Duration = TimeSpan.FromSeconds(10),
Category = withSpotlightRooms && i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal,
Password = withPassword ? @"password" : null,
PlaylistItemStats = new Room.RoomPlaylistItemStats { RulesetIDs = [ruleset.OnlineID] },
Playlist = [new PlaylistItem(new BeatmapInfo { Metadata = new BeatmapMetadata() }) { RulesetID = ruleset.OnlineID }]
});
}
}
public void AddRoom(Room room)
{
room.RoomID = -currentRoomId;
var req = new CreateRoomRequest(room);
req.Success += AddOrUpdateRoom;
api.Queue(req);
currentRoomId++;
}
}
}

View File

@ -16,7 +16,6 @@ using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.Components;
using osu.Game.Tests.Beatmaps;
using osu.Game.Utils;
@ -29,7 +28,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay
public class TestRoomRequestsHandler
{
public IReadOnlyList<Room> ServerSideRooms => serverSideRooms;
private readonly List<Room> serverSideRooms = new List<Room>();
private int currentRoomId = 1;
@ -37,8 +35,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
private int currentScoreId = 1;
/// <summary>
/// Handles an API request, while also updating the local state to match
/// how the server would eventually respond and update an <see cref="RoomManager"/>.
/// Handles an API request, while also updating the local state to match how the server would eventually respond.
/// </summary>
/// <param name="request">The API request to handle.</param>
/// <param name="localUser">The local user to store in responses where required.</param>