diff --git a/osu.Android.props b/osu.Android.props
index 28fbdb3367..2a6bfa0f88 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game/Online/API/Requests/GetRoomRequest.cs b/osu.Game/Online/API/Requests/GetRoomRequest.cs
new file mode 100644
index 0000000000..531e1857de
--- /dev/null
+++ b/osu.Game/Online/API/Requests/GetRoomRequest.cs
@@ -0,0 +1,19 @@
+// 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.Online.Multiplayer;
+
+namespace osu.Game.Online.API.Requests
+{
+ public class GetRoomRequest : APIRequest
+ {
+ private readonly int roomId;
+
+ public GetRoomRequest(int roomId)
+ {
+ this.roomId = roomId;
+ }
+
+ protected override string Target => $"rooms/{roomId}";
+ }
+}
diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs
index c55822c407..d074ac9775 100644
--- a/osu.Game/Online/Multiplayer/Room.cs
+++ b/osu.Game/Online/Multiplayer/Room.cs
@@ -59,8 +59,8 @@ namespace osu.Game.Online.Multiplayer
public Bindable MaxParticipants { get; private set; } = new Bindable();
[Cached]
- [JsonIgnore]
- public BindableList Participants { get; private set; } = new BindableList();
+ [JsonProperty("recent_participants")]
+ public BindableList RecentParticipants { get; private set; } = new BindableList();
[Cached]
public Bindable ParticipantCount { get; private set; } = new Bindable();
@@ -124,10 +124,10 @@ namespace osu.Game.Online.Multiplayer
Playlist.AddRange(other.Playlist);
}
- if (!Participants.SequenceEqual(other.Participants))
+ if (!RecentParticipants.SequenceEqual(other.RecentParticipants))
{
- Participants.Clear();
- Participants.AddRange(other.Participants);
+ RecentParticipants.Clear();
+ RecentParticipants.AddRange(other.RecentParticipants);
}
Position = other.Position;
diff --git a/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs
index 457f064f89..9edb18e065 100644
--- a/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs
@@ -22,11 +22,6 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
Bindable = frameworkConfig.GetBindable(FrameworkSetting.ShowLogOverlay)
},
new SettingsCheckbox
- {
- LabelText = "Performance logging",
- Bindable = config.GetBindable(DebugSetting.PerformanceLogging)
- },
- new SettingsCheckbox
{
LabelText = "Bypass front-to-back render pass",
Bindable = config.GetBindable(DebugSetting.BypassFrontToBackPass)
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs
index 7317076c54..69ff9b43e5 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs
@@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
+using osu.Framework.Platform;
using osu.Game.Configuration;
namespace osu.Game.Overlays.Settings.Sections.Graphics
@@ -24,6 +25,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
LabelText = "Frame limiter",
Bindable = config.GetBindable(FrameworkSetting.FrameSync)
},
+ new SettingsEnumDropdown
+ {
+ LabelText = "Threading mode",
+ Bindable = config.GetBindable(FrameworkSetting.ExecutionMode)
+ },
new SettingsCheckbox
{
LabelText = "Show FPS",
diff --git a/osu.Game/Screens/Multi/Components/OverlinedParticipants.cs b/osu.Game/Screens/Multi/Components/OverlinedParticipants.cs
index a709c6a57a..eb1782d147 100644
--- a/osu.Game/Screens/Multi/Components/OverlinedParticipants.cs
+++ b/osu.Game/Screens/Multi/Components/OverlinedParticipants.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Screens.Multi.Components
}
public OverlinedParticipants(Direction direction)
- : base("Participants")
+ : base("Recent participants")
{
OsuScrollContainer scroll;
ParticipantsList list;
diff --git a/osu.Game/Screens/Multi/Components/ParticipantsList.cs b/osu.Game/Screens/Multi/Components/ParticipantsList.cs
index e383e0414b..5a2dc19b66 100644
--- a/osu.Game/Screens/Multi/Components/ParticipantsList.cs
+++ b/osu.Game/Screens/Multi/Components/ParticipantsList.cs
@@ -1,15 +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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Threading;
using osu.Game.Graphics;
-using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Users;
using osu.Game.Users.Drawables;
using osuTK;
@@ -26,7 +24,9 @@ namespace osu.Game.Screens.Multi.Components
set
{
base.RelativeSizeAxes = value;
- fill.RelativeSizeAxes = value;
+
+ if (tiles != null)
+ tiles.RelativeSizeAxes = value;
}
}
@@ -36,83 +36,75 @@ namespace osu.Game.Screens.Multi.Components
set
{
base.AutoSizeAxes = value;
- fill.AutoSizeAxes = value;
+
+ if (tiles != null)
+ tiles.AutoSizeAxes = value;
}
}
+ private FillDirection direction = FillDirection.Full;
+
public FillDirection Direction
{
- get => fill.Direction;
- set => fill.Direction = value;
- }
+ get => direction;
+ set
+ {
+ direction = value;
- private readonly FillFlowContainer fill;
-
- public ParticipantsList()
- {
- InternalChild = fill = new FillFlowContainer { Spacing = new Vector2(10) };
+ if (tiles != null)
+ tiles.Direction = value;
+ }
}
[BackgroundDependencyLoader]
private void load()
{
- RoomID.BindValueChanged(_ => updateParticipants(), true);
+ RecentParticipants.CollectionChanged += (_, __) => updateParticipants();
+ updateParticipants();
}
- [Resolved]
- private IAPIProvider api { get; set; }
-
- private GetRoomScoresRequest request;
+ private ScheduledDelegate scheduledUpdate;
+ private FillFlowContainer tiles;
private void updateParticipants()
{
- var roomId = RoomID.Value ?? 0;
-
- request?.Cancel();
-
- // nice little progressive fade
- int time = 500;
-
- foreach (var c in fill.Children)
+ scheduledUpdate?.Cancel();
+ scheduledUpdate = Schedule(() =>
{
- c.Delay(500 - time).FadeOut(time, Easing.Out);
- time = Math.Max(20, time - 20);
- c.Expire();
- }
+ tiles?.FadeOut(250, Easing.Out).Expire();
- if (roomId == 0) return;
+ tiles = new FillFlowContainer
+ {
+ Alpha = 0,
+ Direction = Direction,
+ AutoSizeAxes = AutoSizeAxes,
+ RelativeSizeAxes = RelativeSizeAxes,
+ Spacing = new Vector2(10)
+ };
- request = new GetRoomScoresRequest(roomId);
- request.Success += scores => Schedule(() =>
- {
- if (roomId != RoomID.Value)
- return;
+ for (int i = 0; i < RecentParticipants.Count; i++)
+ tiles.Add(new UserTile { User = RecentParticipants[i] });
- fill.Clear();
- foreach (var s in scores)
- fill.Add(new UserTile(s.User));
+ AddInternal(tiles);
- fill.FadeInFromZero(1000, Easing.OutQuint);
+ tiles.Delay(250).FadeIn(250, Easing.OutQuint);
});
-
- api.Queue(request);
- }
-
- protected override void Dispose(bool isDisposing)
- {
- request?.Cancel();
- base.Dispose(isDisposing);
}
private class UserTile : CompositeDrawable, IHasTooltip
{
- private readonly User user;
-
- public string TooltipText => user.Username;
-
- public UserTile(User user)
+ public User User
+ {
+ get => avatar.User;
+ set => avatar.User = value;
+ }
+
+ public string TooltipText => User?.Username ?? string.Empty;
+
+ private readonly UpdateableAvatar avatar;
+
+ public UserTile()
{
- this.user = user;
Size = new Vector2(TILE_SIZE);
CornerRadius = 5f;
Masking = true;
@@ -124,11 +116,7 @@ namespace osu.Game.Screens.Multi.Components
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"27252d"),
},
- new UpdateableAvatar
- {
- RelativeSizeAxes = Axes.Both,
- User = user,
- },
+ avatar = new UpdateableAvatar { RelativeSizeAxes = Axes.Both },
};
}
}
diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
index 64618a1d85..f14aa5fd8c 100644
--- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
+++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
private Bindable filter { get; set; }
[Resolved]
- private Bindable currentRoom { get; set; }
+ private Bindable selectedRoom { get; set; }
[Resolved]
private IRoomManager roomManager { get; set; }
@@ -122,7 +122,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
else
roomFlow.Children.ForEach(r => r.State = r.Room == room ? SelectionState.Selected : SelectionState.NotSelected);
- currentRoom.Value = room;
+ selectedRoom.Value = room;
}
protected override void Dispose(bool isDisposing)
diff --git a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
index e2e5b1b549..7c10f0f975 100644
--- a/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
+++ b/osu.Game/Screens/Multi/Lounge/LoungeSubScreen.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Screens.Multi.Lounge
private readonly LoadingLayer loadingLayer;
[Resolved]
- private Bindable currentRoom { get; set; }
+ private Bindable selectedRoom { get; set; }
public LoungeSubScreen()
{
@@ -101,8 +101,8 @@ namespace osu.Game.Screens.Multi.Lounge
{
base.OnResuming(last);
- if (currentRoom.Value?.RoomID.Value == null)
- currentRoom.Value = new Room();
+ if (selectedRoom.Value?.RoomID.Value == null)
+ selectedRoom.Value = new Room();
onReturning();
}
@@ -143,7 +143,7 @@ namespace osu.Game.Screens.Multi.Lounge
if (!this.IsCurrentScreen())
return;
- currentRoom.Value = room;
+ selectedRoom.Value = room;
this.Push(new MatchSubScreen(room));
}
diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs
index 1219919425..b0d773869a 100644
--- a/osu.Game/Screens/Multi/Multiplayer.cs
+++ b/osu.Game/Screens/Multi/Multiplayer.cs
@@ -48,7 +48,7 @@ namespace osu.Game.Screens.Multi
private readonly IBindable isIdle = new BindableBool();
[Cached]
- private readonly Bindable currentRoom = new Bindable();
+ private readonly Bindable selectedRoom = new Bindable();
[Cached]
private readonly Bindable currentFilter = new Bindable(new FilterCriteria());
@@ -163,14 +163,39 @@ namespace osu.Game.Screens.Multi
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new CachedModelDependencyContainer(base.CreateChildDependencies(parent));
- dependencies.Model.BindTo(currentRoom);
+ dependencies.Model.BindTo(selectedRoom);
return dependencies;
}
private void updatePollingRate(bool idle)
{
- roomManager.TimeBetweenPolls = !this.IsCurrentScreen() || !(screenStack.CurrentScreen is LoungeSubScreen) ? 0 : (idle ? 120000 : 15000);
- Logger.Log($"Polling adjusted to {roomManager.TimeBetweenPolls}");
+ if (!this.IsCurrentScreen())
+ {
+ roomManager.TimeBetweenListingPolls = 0;
+ roomManager.TimeBetweenSelectionPolls = 0;
+ }
+ else
+ {
+ switch (screenStack.CurrentScreen)
+ {
+ case LoungeSubScreen _:
+ roomManager.TimeBetweenListingPolls = idle ? 120000 : 15000;
+ roomManager.TimeBetweenSelectionPolls = idle ? 120000 : 15000;
+ break;
+
+ case MatchSubScreen _:
+ roomManager.TimeBetweenListingPolls = 0;
+ roomManager.TimeBetweenSelectionPolls = idle ? 30000 : 5000;
+ break;
+
+ default:
+ roomManager.TimeBetweenListingPolls = 0;
+ roomManager.TimeBetweenSelectionPolls = 0;
+ break;
+ }
+ }
+
+ Logger.Log($"Polling adjusted (listing: {roomManager.TimeBetweenListingPolls}, selection: {roomManager.TimeBetweenSelectionPolls})");
}
///
@@ -222,6 +247,8 @@ namespace osu.Game.Screens.Multi
base.OnResuming(last);
beginHandlingTrack();
+
+ updatePollingRate(isIdle.Value);
}
public override void OnSuspending(IScreen next)
@@ -231,7 +258,7 @@ namespace osu.Game.Screens.Multi
endHandlingTrack();
- roomManager.TimeBetweenPolls = 0;
+ updatePollingRate(isIdle.Value);
}
public override bool OnExiting(IScreen next)
diff --git a/osu.Game/Screens/Multi/MultiplayerComposite.cs b/osu.Game/Screens/Multi/MultiplayerComposite.cs
index 3f048eceab..e612e77748 100644
--- a/osu.Game/Screens/Multi/MultiplayerComposite.cs
+++ b/osu.Game/Screens/Multi/MultiplayerComposite.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.Multi
protected BindableList Playlist { get; private set; }
[Resolved(typeof(Room))]
- protected BindableList Participants { get; private set; }
+ protected BindableList RecentParticipants { get; private set; }
[Resolved(typeof(Room))]
protected Bindable ParticipantCount { get; private set; }
diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs
index cdaba85b9e..ad461af57f 100644
--- a/osu.Game/Screens/Multi/RoomManager.cs
+++ b/osu.Game/Screens/Multi/RoomManager.cs
@@ -2,10 +2,13 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Online;
@@ -17,20 +20,24 @@ using osu.Game.Screens.Multi.Lounge.Components;
namespace osu.Game.Screens.Multi
{
- public class RoomManager : PollingComponent, IRoomManager
+ public class RoomManager : CompositeDrawable, IRoomManager
{
public event Action RoomsUpdated;
private readonly BindableList rooms = new BindableList();
public IBindableList Rooms => rooms;
- private Room joinedRoom;
+ public double TimeBetweenListingPolls
+ {
+ get => listingPollingComponent.TimeBetweenPolls;
+ set => listingPollingComponent.TimeBetweenPolls = value;
+ }
- [Resolved]
- private Bindable currentFilter { get; set; }
-
- [Resolved]
- private IAPIProvider api { get; set; }
+ public double TimeBetweenSelectionPolls
+ {
+ get => selectionPollingComponent.TimeBetweenPolls;
+ set => selectionPollingComponent.TimeBetweenPolls = value;
+ }
[Resolved]
private RulesetStore rulesets { get; set; }
@@ -38,14 +45,26 @@ namespace osu.Game.Screens.Multi
[Resolved]
private BeatmapManager beatmaps { get; set; }
- [BackgroundDependencyLoader]
- private void load()
+ [Resolved]
+ private IAPIProvider api { get; set; }
+
+ [Resolved]
+ private Bindable selectedRoom { get; set; }
+
+ private readonly ListingPollingComponent listingPollingComponent;
+ private readonly SelectionPollingComponent selectionPollingComponent;
+
+ private Room joinedRoom;
+
+ public RoomManager()
{
- currentFilter.BindValueChanged(_ =>
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
{
- if (IsLoaded)
- PollImmediately();
- });
+ listingPollingComponent = new ListingPollingComponent { RoomsReceived = onListingReceived },
+ selectionPollingComponent = new SelectionPollingComponent { RoomReceived = onSelectedRoomReceived }
+ };
}
protected override void Dispose(bool isDisposing)
@@ -116,45 +135,52 @@ namespace osu.Game.Screens.Multi
joinedRoom = null;
}
- private GetRoomsRequest pollReq;
-
- protected override Task Poll()
+ ///
+ /// Invoked when the listing of all s is received from the server.
+ ///
+ /// The listing.
+ private void onListingReceived(List listing)
{
- if (!api.IsLoggedIn)
- return base.Poll();
-
- var tcs = new TaskCompletionSource();
-
- pollReq?.Cancel();
- pollReq = new GetRoomsRequest(currentFilter.Value.PrimaryFilter);
-
- pollReq.Success += result =>
+ // Remove past matches
+ foreach (var r in rooms.ToList())
{
- // Remove past matches
- foreach (var r in rooms.ToList())
+ if (listing.All(e => e.RoomID.Value != r.RoomID.Value))
+ rooms.Remove(r);
+ }
+
+ for (int i = 0; i < listing.Count; i++)
+ {
+ if (selectedRoom.Value?.RoomID?.Value == listing[i].RoomID.Value)
{
- if (result.All(e => e.RoomID.Value != r.RoomID.Value))
- rooms.Remove(r);
+ // The listing request contains less data than the selection request, so data from the selection request is always preferred while the room is selected.
+ continue;
}
- for (int i = 0; i < result.Count; i++)
+ var r = listing[i];
+ r.Position.Value = i;
+
+ update(r, r);
+ addRoom(r);
+ }
+
+ RoomsUpdated?.Invoke();
+ }
+
+ ///
+ /// Invoked when a is received from the server.
+ ///
+ /// The received .
+ private void onSelectedRoomReceived(Room toUpdate)
+ {
+ foreach (var room in rooms)
+ {
+ if (room.RoomID.Value == toUpdate.RoomID.Value)
{
- var r = result[i];
- r.Position.Value = i;
-
- update(r, r);
- addRoom(r);
+ toUpdate.Position.Value = room.Position.Value;
+ update(room, toUpdate);
+ break;
}
-
- RoomsUpdated?.Invoke();
- tcs.SetResult(true);
- };
-
- pollReq.Failure += _ => tcs.SetResult(false);
-
- api.Queue(pollReq);
-
- return tcs.Task;
+ }
}
///
@@ -182,5 +208,100 @@ namespace osu.Game.Screens.Multi
else
existing.CopyFrom(room);
}
+
+ private class SelectionPollingComponent : PollingComponent
+ {
+ public Action RoomReceived;
+
+ [Resolved]
+ private IAPIProvider api { get; set; }
+
+ [Resolved]
+ private Bindable selectedRoom { get; set; }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ selectedRoom.BindValueChanged(_ =>
+ {
+ if (IsLoaded)
+ PollImmediately();
+ });
+ }
+
+ private GetRoomRequest pollReq;
+
+ protected override Task Poll()
+ {
+ if (!api.IsLoggedIn)
+ return base.Poll();
+
+ if (selectedRoom.Value?.RoomID.Value == null)
+ return base.Poll();
+
+ var tcs = new TaskCompletionSource();
+
+ pollReq?.Cancel();
+ pollReq = new GetRoomRequest(selectedRoom.Value.RoomID.Value.Value);
+
+ pollReq.Success += result =>
+ {
+ RoomReceived?.Invoke(result);
+ tcs.SetResult(true);
+ };
+
+ pollReq.Failure += _ => tcs.SetResult(false);
+
+ api.Queue(pollReq);
+
+ return tcs.Task;
+ }
+ }
+
+ private class ListingPollingComponent : PollingComponent
+ {
+ public Action> RoomsReceived;
+
+ [Resolved]
+ private IAPIProvider api { get; set; }
+
+ [Resolved]
+ private Bindable currentFilter { get; set; }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ currentFilter.BindValueChanged(_ =>
+ {
+ if (IsLoaded)
+ PollImmediately();
+ });
+ }
+
+ private GetRoomsRequest pollReq;
+
+ protected override Task Poll()
+ {
+ if (!api.IsLoggedIn)
+ return base.Poll();
+
+ var tcs = new TaskCompletionSource();
+
+ pollReq?.Cancel();
+ pollReq = new GetRoomsRequest(currentFilter.Value.PrimaryFilter);
+
+ pollReq.Success += result =>
+ {
+ RoomsReceived?.Invoke(result);
+ tcs.SetResult(true);
+ };
+
+ pollReq.Failure += _ => tcs.SetResult(false);
+
+ api.Queue(pollReq);
+
+ return tcs.Task;
+ }
+ }
}
}
diff --git a/osu.Game/Users/User.cs b/osu.Game/Users/User.cs
index c573fdd089..d25c552160 100644
--- a/osu.Game/Users/User.cs
+++ b/osu.Game/Users/User.cs
@@ -9,7 +9,7 @@ using osu.Framework.Bindables;
namespace osu.Game.Users
{
- public class User
+ public class User : IEquatable
{
[JsonProperty(@"id")]
public long Id = 1;
@@ -244,5 +244,13 @@ namespace osu.Game.Users
[Description("Touch Screen")]
Touch,
}
+
+ public bool Equals(User other)
+ {
+ if (ReferenceEquals(null, other)) return false;
+ if (ReferenceEquals(this, other)) return true;
+
+ return Id == other.Id;
+ }
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index c5ebf0f712..ca62a959d9 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index abd562dc81..11e7991dfa 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -71,7 +71,7 @@
-
+
@@ -79,7 +79,7 @@
-
+