1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-13 08:32:57 +08:00

Make RoomID non-bindable

Most important changes are to `RoomSubScreen` and `PlaylistsRoomSubScreen`, because those are the only two cases that now bind to the event instead.
This commit is contained in:
Dan Balasescu 2024-11-13 16:28:39 +09:00
parent db025d81ee
commit 99762da7b8
No known key found for this signature in database
35 changed files with 176 additions and 167 deletions

View File

@ -75,7 +75,7 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
var newRoom = new Room();
newRoom.CopyFrom(SelectedRoom.Value);
newRoom.RoomID.Value = null;
newRoom.RoomID = null;
MultiplayerClient.RoomSetupAction = room =>
{
room.State = MultiplayerRoomState.Playing;

View File

@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
{
var room = new Room
{
RoomID = { Value = 1234 },
RoomID = 1234,
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
{
@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
{
var room = new Room
{
RoomID = { Value = 1234 },
RoomID = 1234,
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
{
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
{
var room = new Room
{
RoomID = { Value = 1234 },
RoomID = 1234,
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
{

View File

@ -68,7 +68,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
{
API.Perform(new CreateRoomRequest(room = new Room
{
RoomID = { Value = roomId },
RoomID = roomId,
Name = { Value = "Daily Challenge: June 4, 2024" },
Playlist =
{

View File

@ -43,7 +43,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
return false;
};
});
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = { Value = 1 } }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = 1 }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
@ -86,7 +86,7 @@ namespace osu.Game.Tests.Visual.DailyChallenge
return false;
};
});
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = { Value = 1 } }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = 1 }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Menus
beatmap.OnlineID = 1001;
getRoomRequest.TriggerSuccess(new Room
{
RoomID = { Value = 1234 },
RoomID = 1234,
Name = { Value = "Aug 8, 2024" },
Playlist =
{

View File

@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("create leaderboard", () =>
{
SelectedRoom.Value = new Room { RoomID = { Value = 3 } };
SelectedRoom.Value = new Room { RoomID = 3 };
Child = new MatchLeaderboard
{

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Playlists
AddStep("create list", () =>
{
SelectedRoom.Value = new Room { RoomID = { Value = 7 } };
SelectedRoom.Value = new Room { RoomID = 7 };
for (int i = 0; i < 50; i++)
{

View File

@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.UserInterface
beatmap.OnlineID = 1001;
getRoomRequest.TriggerSuccess(new Room
{
RoomID = { Value = 1234 },
RoomID = 1234,
Playlist =
{
new PlaylistItem(beatmap)
@ -131,7 +131,7 @@ namespace osu.Game.Tests.Visual.UserInterface
beatmap.OnlineID = 1001;
getRoomRequest.TriggerSuccess(new Room
{
RoomID = { Value = 1234 },
RoomID = 1234,
Playlist =
{
new PlaylistItem(beatmap)

View File

@ -181,10 +181,10 @@ namespace osu.Game.Online.Multiplayer
await joinOrLeaveTaskChain.Add(async () =>
{
Debug.Assert(room.RoomID.Value != null);
Debug.Assert(room.RoomID != null);
// Join the server-side room.
var joinedRoom = await JoinRoom(room.RoomID.Value.Value, password ?? room.Password.Value).ConfigureAwait(false);
var joinedRoom = await JoinRoom(room.RoomID.Value, password ?? room.Password.Value).ConfigureAwait(false);
Debug.Assert(joinedRoom != null);
// Populate users.

View File

@ -27,6 +27,6 @@ namespace osu.Game.Online.Rooms
return req;
}
protected override string Target => $@"rooms/{Room.RoomID.Value}/users/{User!.Id}";
protected override string Target => $@"rooms/{Room.RoomID}/users/{User!.Id}";
}
}

View File

@ -23,6 +23,6 @@ namespace osu.Game.Online.Rooms
return req;
}
protected override string Target => $"rooms/{room.RoomID.Value}/users/{User!.Id}";
protected override string Target => $"rooms/{room.RoomID}/users/{User!.Id}";
}
}

View File

@ -21,6 +21,15 @@ namespace osu.Game.Online.Rooms
{
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// The online room ID. Will be <c>null</c> while the room has not yet been created.
/// </summary>
public long? RoomID
{
get => roomId;
set => SetField(ref roomId, value);
}
/// <summary>
/// Represents the current item selected within the room.
/// </summary>
@ -33,13 +42,12 @@ namespace osu.Game.Online.Rooms
set => SetField(ref currentPlaylistItem, value);
}
[JsonProperty("id")]
private long? roomId;
[JsonProperty("current_playlist_item")]
private PlaylistItem? currentPlaylistItem;
[Cached]
[JsonProperty("id")]
public readonly Bindable<long?> RoomID = new Bindable<long?>();
[Cached]
[JsonProperty("name")]
public readonly Bindable<string> Name = new Bindable<string>();
@ -196,7 +204,7 @@ namespace osu.Game.Online.Rooms
/// <param name="other">The <see cref="Room"/> to copy values from.</param>
public void CopyFrom(Room other)
{
RoomID.Value = other.RoomID.Value;
RoomID = other.RoomID;
Name.Value = other.Name.Value;
Category.Value = other.Category.Value;

View File

@ -155,9 +155,9 @@ namespace osu.Game.Screens.Menu
Room = room;
cover.OnlineInfo = TooltipContent = room.Playlist.FirstOrDefault()?.Beatmap.BeatmapSet as APIBeatmapSet;
if (room.StartDate.Value != null && room.RoomID.Value != lastDailyChallengeRoomID)
if (room.StartDate.Value != null && room.RoomID != lastDailyChallengeRoomID)
{
lastDailyChallengeRoomID = room.RoomID.Value;
lastDailyChallengeRoomID = room.RoomID;
// new challenge is live, reset intro played static.
statics.SetValue(Static.DailyChallengeIntroPlayed, false);

View File

@ -1,13 +1,10 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Development;
@ -20,18 +17,17 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
public partial class RoomManager : Component, IRoomManager
{
[CanBeNull]
public event Action RoomsUpdated;
public event Action? RoomsUpdated;
private readonly BindableList<Room> rooms = new BindableList<Room>();
public IBindableList<Room> Rooms => rooms;
protected IBindable<Room> JoinedRoom => joinedRoom;
private readonly Bindable<Room> joinedRoom = new Bindable<Room>();
protected IBindable<Room?> JoinedRoom => joinedRoom;
private readonly Bindable<Room?> joinedRoom = new Bindable<Room?>();
[Resolved]
private IAPIProvider api { get; set; }
private IAPIProvider api { get; set; } = null!;
public RoomManager()
{
@ -44,7 +40,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
PartRoom();
}
public virtual void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null)
public virtual void CreateRoom(Room room, Action<Room>? onSuccess = null, Action<string>? onError = null)
{
room.Host.Value = api.LocalUser.Value;
@ -69,9 +65,9 @@ namespace osu.Game.Screens.OnlinePlay.Components
api.Queue(req);
}
private JoinRoomRequest currentJoinRoomRequest;
private JoinRoomRequest? currentJoinRoomRequest;
public virtual void JoinRoom(Room room, string password = null, Action<Room> onSuccess = null, Action<string> onError = null)
public virtual void JoinRoom(Room room, string? password = null, Action<Room>? onSuccess = null, Action<string>? onError = null)
{
currentJoinRoomRequest?.Cancel();
currentJoinRoomRequest = new JoinRoomRequest(room, password);
@ -97,7 +93,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
currentJoinRoomRequest?.Cancel();
if (JoinedRoom.Value == null)
if (joinedRoom.Value == null)
return;
if (api.State.Value == APIState.Online)
@ -111,14 +107,14 @@ namespace osu.Game.Screens.OnlinePlay.Components
public void AddOrUpdateRoom(Room room)
{
Debug.Assert(ThreadSafety.IsUpdateThread);
Debug.Assert(room.RoomID.Value != null);
Debug.Assert(room.RoomID != null);
if (ignoredRooms.Contains(room.RoomID.Value.Value))
if (ignoredRooms.Contains(room.RoomID.Value))
return;
try
{
var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value);
var existing = rooms.FirstOrDefault(e => e.RoomID == room.RoomID);
if (existing == null)
rooms.Add(room);
else
@ -128,7 +124,7 @@ namespace osu.Game.Screens.OnlinePlay.Components
{
Logger.Error(ex, $"Failed to update room: {room.Name.Value}.");
ignoredRooms.Add(room.RoomID.Value.Value);
ignoredRooms.Add(room.RoomID.Value);
rooms.Remove(room);
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Threading.Tasks;
using osu.Game.Online.Rooms;
@ -20,21 +18,21 @@ namespace osu.Game.Screens.OnlinePlay.Components
this.room = room;
}
private GetRoomRequest lastPollRequest;
private GetRoomRequest? lastPollRequest;
protected override Task Poll()
{
if (!API.IsLoggedIn)
return base.Poll();
if (room.RoomID.Value == null)
if (room.RoomID == null)
return base.Poll();
var tcs = new TaskCompletionSource<bool>();
lastPollRequest?.Cancel();
var req = new GetRoomRequest(room.RoomID.Value.Value);
var req = new GetRoomRequest(room.RoomID.Value);
req.Success += result =>
{

View File

@ -353,12 +353,12 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
private void presentScore(long id)
{
if (this.IsCurrentScreen())
this.Push(new PlaylistItemScoreResultsScreen(room.RoomID.Value!.Value, playlistItem, id));
this.Push(new PlaylistItemScoreResultsScreen(room.RoomID!.Value, playlistItem, id));
}
private void onRoomScoreSet(MultiplayerRoomScoreSetEvent e)
{
if (e.RoomID != room.RoomID.Value || e.PlaylistItemID != playlistItem.ID)
if (e.RoomID != room.RoomID || e.PlaylistItemID != playlistItem.ID)
return;
userLookupCache.GetUserAsync(e.UserID).ContinueWith(t =>
@ -410,7 +410,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
private void dailyChallengeChanged(ValueChangedEvent<DailyChallengeInfo?> change)
{
if (change.OldValue?.RoomID == room.RoomID.Value && change.NewValue == null && metadataClient.IsConnected.Value)
if (change.OldValue?.RoomID == room.RoomID && change.NewValue == null && metadataClient.IsConnected.Value)
{
notificationOverlay?.Post(new SimpleNotification { Text = DailyChallengeStrings.ChallengeEndedNotification });
}
@ -437,7 +437,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
roomManager.JoinRoom(room);
startLoopingTrack(this, musicController);
metadataClient.BeginWatchingMultiplayerRoom(room.RoomID.Value!.Value).ContinueWith(t =>
metadataClient.BeginWatchingMultiplayerRoom(room.RoomID!.Value).ContinueWith(t =>
{
if (t.Exception != null)
{
@ -489,7 +489,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
this.Delay(WaveContainer.DISAPPEAR_DURATION).FadeOut();
roomManager.PartRoom();
metadataClient.EndWatchingMultiplayerRoom(room.RoomID.Value!.Value).FireAndForget();
metadataClient.EndWatchingMultiplayerRoom(room.RoomID!.Value).FireAndForget();
return base.OnExiting(e);
}

View File

@ -138,7 +138,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
if (request?.CompletionState == APIRequestCompletionState.Waiting)
return;
request = new IndexPlaylistScoresRequest(room.RoomID.Value!.Value, playlistItem.ID);
request = new IndexPlaylistScoresRequest(room.RoomID!.Value, playlistItem.ID);
request.Success += req => Schedule(() =>
{

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@ -11,6 +9,7 @@ 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;
@ -24,8 +23,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
public partial class RoomsContainer : CompositeDrawable, IKeyBindingHandler<GlobalAction>
{
public readonly Bindable<Room> SelectedRoom = new Bindable<Room>();
public readonly Bindable<FilterCriteria> Filter = new Bindable<FilterCriteria>();
public readonly Bindable<Room?> SelectedRoom = new Bindable<Room?>();
public readonly Bindable<FilterCriteria?> Filter = new Bindable<FilterCriteria?>();
public IReadOnlyList<DrawableRoom> Rooms => roomFlow.FlowingChildren.Cast<DrawableRoom>().ToArray();
@ -33,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private readonly FillFlowContainer<DrawableLoungeRoom> roomFlow;
[Resolved]
private IRoomManager roomManager { get; set; }
private IRoomManager roomManager { get; set; } = null!;
// handle deselection
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
@ -67,10 +66,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
rooms.BindTo(roomManager.Rooms);
Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
Filter.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true);
}
private void applyFilterCriteria(FilterCriteria criteria)
private void applyFilterCriteria(FilterCriteria? criteria)
{
roomFlow.Children.ForEach(r =>
{
@ -113,7 +112,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
}
}
private void roomsChanged(object sender, NotifyCollectionChangedEventArgs args)
private void roomsChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
switch (args.Action)
{
@ -142,7 +141,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
foreach (var room in rooms)
roomFlow.Add(new DrawableLoungeRoom(room) { SelectedRoom = SelectedRoom });
applyFilterCriteria(Filter?.Value);
applyFilterCriteria(Filter.Value);
}
private void removeRooms(IEnumerable<Room> rooms)
@ -173,7 +172,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
roomFlow.SetLayoutPosition(room, room.Room.Category.Value > RoomCategory.Normal
// Always show spotlight playlists at the top of the listing.
? float.MinValue
: -(room.Room.RoomID.Value ?? 0));
: -(room.Room.RoomID ?? 0));
}
}
@ -213,7 +212,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
var visibleRooms = Rooms.AsEnumerable().Where(r => r.IsPresent);
Room room;
Room? room;
if (SelectedRoom.Value == null)
room = visibleRooms.FirstOrDefault()?.Room;
@ -236,7 +235,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
base.Dispose(isDisposing);
if (roomManager != null)
if (roomManager.IsNotNull())
roomManager.RoomsUpdated -= updateSorting;
}
}

View File

@ -259,7 +259,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
selectionLease.Return();
selectionLease = null;
if (SelectedRoom.Value?.RoomID.Value == null)
if (SelectedRoom.Value?.RoomID == null)
SelectedRoom.Value = new Room();
music?.EnsurePlayingSomething();
@ -326,19 +326,19 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
/// <param name="room">The room to copy.</param>
public void OpenCopy(Room room)
{
Debug.Assert(room.RoomID.Value != null);
Debug.Assert(room.RoomID != null);
if (joiningRoomOperation != null)
return;
joiningRoomOperation = ongoingOperationTracker?.BeginOperation();
var req = new GetRoomRequest(room.RoomID.Value.Value);
var req = new GetRoomRequest(room.RoomID.Value);
req.Success += r =>
{
// ID must be unset as we use this as a marker for whether this is a client-side (not-yet-created) room or not.
r.RoomID.Value = null;
r.RoomID = null;
// Null out dates because end date is not supported client-side and the settings overlay will populate a duration.
r.EndDate.Value = null;

View File

@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
private void updateChannel()
{
if (room.RoomID.Value == null || channelId.Value == 0)
if (room.RoomID == null || channelId.Value == 0)
return;
Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#lazermp_{room.RoomID.Value}" });

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -23,7 +21,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components
protected const float TRANSITION_DURATION = 350;
protected const float FIELD_PADDING = 25;
protected OnlinePlayComposite Settings { get; set; }
protected OnlinePlayComposite Settings { get; set; } = null!;
protected override bool BlockScrollInput => false;

View File

@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
@ -29,6 +30,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Menu;
using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Screens.OnlinePlay.Match
{
@ -59,8 +61,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
/// </summary>
protected readonly Bindable<IReadOnlyList<Mod>> UserMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
protected readonly IBindable<long?> RoomId = new Bindable<long?>();
[Resolved(CanBeNull = true)]
private IOverlayManager overlayManager { get; set; }
@ -82,6 +82,9 @@ namespace osu.Game.Screens.OnlinePlay.Match
[Resolved]
private PreviewTrackManager previewTrackManager { get; set; } = null!;
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
[Cached]
private readonly OnlinePlayBeatmapAvailabilityTracker beatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker();
@ -109,8 +112,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
this.allowEdit = allowEdit;
Padding = new MarginPadding { Top = Header.HEIGHT };
RoomId.BindTo(room.RoomID);
}
[BackgroundDependencyLoader]
@ -252,22 +253,6 @@ namespace osu.Game.Screens.OnlinePlay.Match
{
base.LoadComplete();
RoomId.BindValueChanged(id =>
{
if (id.NewValue == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.Show();
}
else
{
mainContent.Show();
settingsOverlay.Hide();
}
}, true);
SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged));
UserMods.BindValueChanged(_ => Scheduler.AddOnce(UpdateMods));
@ -275,6 +260,31 @@ namespace osu.Game.Screens.OnlinePlay.Match
beatmapAvailabilityTracker.Availability.BindValueChanged(_ => updateWorkingBeatmap());
userModsSelectOverlayRegistration = overlayManager?.RegisterBlockingOverlay(UserModsSelectOverlay);
Room.PropertyChanged += onRoomPropertyChanged;
updateSetupState();
}
private void onRoomPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.RoomID))
updateSetupState();
}
private void updateSetupState()
{
if (Room.RoomID == null)
{
// A new room is being created.
// The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed.
mainContent.Hide();
settingsOverlay.Show();
}
else
{
mainContent.Show();
settingsOverlay.Hide();
}
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
@ -285,14 +295,11 @@ namespace osu.Game.Screens.OnlinePlay.Match
};
}
[Resolved(canBeNull: true)]
private IDialogOverlay dialogOverlay { get; set; }
protected virtual bool IsConnected => api.State.Value == APIState.Online;
public override bool OnBackButton()
{
if (Room.RoomID.Value == null)
if (Room.RoomID == null)
{
if (!ensureExitConfirmed())
return true;
@ -365,7 +372,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
if (!IsConnected)
return true;
bool hasUnsavedChanges = Room.RoomID.Value == null && Room.Playlist.Count > 0;
bool hasUnsavedChanges = Room.RoomID == null && Room.Playlist.Count > 0;
if (dialogOverlay == null || !hasUnsavedChanges)
return true;
@ -538,6 +545,7 @@ namespace osu.Game.Screens.OnlinePlay.Match
base.Dispose(isDisposing);
userModsSelectOverlayRegistration?.Dispose();
Room.PropertyChanged -= onRoomPropertyChanged;
}
}
}

View File

@ -353,7 +353,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
RoomName.BindValueChanged(name => NameField.Text = name.NewValue, true);
Type.BindValueChanged(type => TypePicker.Current.Value = type.NewValue, true);
MaxParticipants.BindValueChanged(count => MaxParticipantsField.Text = count.NewValue?.ToString(), true);
RoomID.BindValueChanged(roomId => playlistContainer.Alpha = roomId.NewValue == null ? 1 : 0, true);
Password.BindValueChanged(password => PasswordTextBox.Text = password.NewValue ?? string.Empty, true);
QueueMode.BindValueChanged(mode => QueueModeDropdown.Current.Value = mode.NewValue, true);
AutoStartDuration.BindValueChanged(duration => startModeDropdown.Current.Value = (StartMode)(int)duration.NewValue.TotalSeconds, true);
@ -382,6 +381,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match
base.Update();
ApplyButton.Enabled.Value = Playlist.Count > 0 && NameField.Text.Length > 0 && !operationInProgress.Value;
playlistContainer.Alpha = room.RoomID == null ? 1 : 0;
}
private void apply()

View File

@ -54,7 +54,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
public MultiplayerMatchSubScreen(Room room)
: base(room)
{
Title = room.RoomID.Value == null ? "New room" : room.Name.Value;
Title = room.RoomID == null ? "New room" : room.Name.Value;
Activity.Value = new UserActivity.InLobby(room);
}

View File

@ -1,14 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Graphics.UserInterface;
@ -29,17 +28,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
protected override UserActivity InitialActivity => new UserActivity.InMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value);
[Resolved]
private MultiplayerClient client { get; set; }
private MultiplayerClient client { get; set; } = null!;
private IBindable<bool> isConnected;
private IBindable<bool> isConnected = null!;
private readonly TaskCompletionSource<bool> resultsReady = new TaskCompletionSource<bool>();
private readonly MultiplayerRoomUser[] users;
private LoadingLayer loadingDisplay;
private MultiplayerGameplayLeaderboard multiplayerLeaderboard;
private LoadingLayer loadingDisplay = null!;
private MultiplayerGameplayLeaderboard multiplayerLeaderboard = null!;
/// <summary>
/// Construct a multiplayer player.
@ -153,7 +150,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
GameplayClockContainer.Reset();
}
private void failAndBail(string message = null)
private void failAndBail(string? message = null)
{
if (!string.IsNullOrEmpty(message))
Logger.Log(message, LoggingTarget.Runtime, LogLevel.Important);
@ -196,14 +193,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
protected override ResultsScreen CreateResults(ScoreInfo score)
{
Debug.Assert(Room.RoomID.Value != null);
Debug.Assert(Room.RoomID != null);
return multiplayerLeaderboard.TeamScores.Count == 2
? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, multiplayerLeaderboard.TeamScores)
? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value, PlaylistItem, multiplayerLeaderboard.TeamScores)
{
ShowUserStatistics = true,
}
: new MultiplayerResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem)
: new MultiplayerResultsScreen(score, Room.RoomID.Value, PlaylistItem)
{
ShowUserStatistics = true
};
@ -213,7 +210,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
base.Dispose(isDisposing);
if (client != null)
if (client.IsNotNull())
{
client.GameplayStarted -= onGameplayStarted;
client.ResultsReady -= onResultsReady;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Diagnostics;
using osu.Framework.Allocation;
@ -18,12 +16,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
public partial class MultiplayerRoomManager : RoomManager
{
[Resolved]
private MultiplayerClient multiplayerClient { get; set; }
private MultiplayerClient multiplayerClient { get; set; } = null!;
public override void CreateRoom(Room room, Action<Room> onSuccess = null, Action<string> onError = null)
public override void CreateRoom(Room room, Action<Room>? onSuccess = null, Action<string>? onError = null)
=> base.CreateRoom(room, r => joinMultiplayerRoom(r, r.Password.Value, onSuccess, onError), onError);
public override void JoinRoom(Room room, string password = null, Action<Room> onSuccess = null, Action<string> onError = null)
public override void JoinRoom(Room room, string? password = null, Action<Room>? onSuccess = null, Action<string>? onError = null)
{
if (!multiplayerClient.IsConnected.Value)
{
@ -51,9 +49,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
multiplayerClient.LeaveRoom();
}
private void joinMultiplayerRoom(Room room, string password, Action<Room> onSuccess = null, Action<string> onError = null)
private void joinMultiplayerRoom(Room room, string? password, Action<Room>? onSuccess = null, Action<string>? onError = null)
{
Debug.Assert(room.RoomID.Value != null);
Debug.Assert(room.RoomID != null);
multiplayerClient.JoinRoom(room, password).ContinueWith(t =>
{

View File

@ -16,9 +16,6 @@ namespace osu.Game.Screens.OnlinePlay
/// </summary>
public partial class OnlinePlayComposite : CompositeDrawable
{
[Resolved(typeof(Room))]
protected Bindable<long?> RoomID { get; private set; } = null!;
[Resolved(typeof(Room), nameof(Room.Name))]
protected Bindable<string> RoomName { get; private set; } = null!;

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Diagnostics;
using System.Linq;
@ -21,11 +19,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
{
public partial class PlaylistsPlayer : RoomSubmittingPlayer
{
public Action Exited;
public Action? Exited;
protected override UserActivity InitialActivity => new UserActivity.InPlaylistGame(Beatmap.Value.BeatmapInfo, Ruleset.Value);
public PlaylistsPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration configuration = null)
public PlaylistsPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration? configuration = null)
: base(room, playlistItem, configuration)
{
}
@ -57,8 +55,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
protected override ResultsScreen CreateResults(ScoreInfo score)
{
Debug.Assert(Room.RoomID.Value != null);
return new PlaylistItemUserResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem)
Debug.Assert(Room.RoomID != null);
return new PlaylistItemUserResultsScreen(score, Room.RoomID.Value, PlaylistItem)
{
AllowRetry = true,
ShowUserStatistics = true,

View File

@ -372,7 +372,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private void onPlaylistChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
playlistLength.Text = $"Length: {Playlist.GetTotalDuration(rulesets)}";
private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0
private bool hasValidSettings => room.RoomID == null && NameField.Text.Length > 0 && Playlist.Count > 0
&& hasValidDuration;
private bool hasValidDuration => DurationField.Current.Value <= TimeSpan.FromDays(14) || localUser.Value.IsSupporter;

View File

@ -1,11 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -22,6 +20,7 @@ using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Users;
using osuTK;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Screens.OnlinePlay.Playlists
{
@ -33,20 +32,22 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
private readonly IBindable<bool> isIdle = new BindableBool();
private MatchLeaderboard leaderboard;
private SelectionPollingComponent selectionPollingComponent;
[Resolved(CanBeNull = true)]
private IdleTracker? idleTracker { get; set; }
private FillFlowContainer progressSection;
private MatchLeaderboard leaderboard = null!;
private SelectionPollingComponent selectionPollingComponent = null!;
private FillFlowContainer progressSection = null!;
public PlaylistsRoomSubScreen(Room room)
: base(room, false) // Editing is temporarily not allowed.
{
Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value;
Title = room.RoomID == null ? "New playlist" : room.Name.Value;
Activity.Value = new UserActivity.InLobby(room);
}
[BackgroundDependencyLoader(true)]
private void load([CanBeNull] IdleTracker idleTracker)
[BackgroundDependencyLoader]
private void load()
{
if (idleTracker != null)
isIdle.BindTo(idleTracker.IsIdle);
@ -59,17 +60,26 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
base.LoadComplete();
isIdle.BindValueChanged(_ => updatePollingRate(), true);
RoomId.BindValueChanged(id =>
{
if (id.NewValue != null)
{
// Set the first playlist item.
// This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()).
Schedule(() => SelectedItem.Value = Room.Playlist.FirstOrDefault());
}
}, true);
Room.MaxAttempts.BindValueChanged(_ => progressSection.Alpha = Room.MaxAttempts.Value != null ? 1 : 0, true);
Room.PropertyChanged += onRoomPropertyChanged;
updateSetupState();
}
private void onRoomPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Room.RoomID))
updateSetupState();
}
private void updateSetupState()
{
if (Room.RoomID != null)
{
// Set the first playlist item.
// This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()).
Schedule(() => SelectedItem.Value = Room.Playlist.FirstOrDefault());
}
}
protected override Drawable CreateMainContent() => new Container
@ -92,7 +102,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
},
Content = new[]
{
new Drawable[]
new Drawable?[]
{
// Playlist items column
new GridContainer
@ -113,8 +123,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
AllowShowingResults = true,
RequestResults = item =>
{
Debug.Assert(RoomId.Value != null);
ParentScreen?.Push(new PlaylistItemUserResultsScreen(null, RoomId.Value.Value, item));
Debug.Assert(Room.RoomID != null);
ParentScreen?.Push(new PlaylistItemUserResultsScreen(null, Room.RoomID.Value, item));
}
}
},
@ -248,5 +258,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
{
Exited = () => leaderboard.RefetchScores()
});
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
Room.PropertyChanged -= onRoomPropertyChanged;
}
}
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System.Diagnostics;
using osu.Game.Extensions;
using osu.Game.Online.API;
@ -19,16 +17,16 @@ namespace osu.Game.Screens.Play
protected readonly PlaylistItem PlaylistItem;
protected readonly Room Room;
protected RoomSubmittingPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration configuration = null)
protected RoomSubmittingPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration? configuration = null)
: base(configuration)
{
Room = room;
PlaylistItem = playlistItem;
}
protected override APIRequest<APIScoreToken> CreateTokenRequest()
protected override APIRequest<APIScoreToken>? CreateTokenRequest()
{
if (!(Room.RoomID.Value is long roomId))
if (Room.RoomID is not long roomId)
return null;
int beatmapId = Beatmap.Value.BeatmapInfo.OnlineID;
@ -45,8 +43,8 @@ namespace osu.Game.Screens.Play
protected override APIRequest<MultiplayerScore> CreateSubmissionRequest(Score score, long token)
{
Debug.Assert(Room.RoomID.Value != null);
return new SubmitRoomScoreRequest(score.ScoreInfo, token, Room.RoomID.Value.Value, PlaylistItem.ID);
Debug.Assert(Room.RoomID != null);
return new SubmitRoomScoreRequest(score.ScoreInfo, token, Room.RoomID.Value, PlaylistItem.ID);
}
}
}

View File

@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
roomId = clone(roomId);
password = clone(password);
ServerAPIRoom = roomManager.ServerSideRooms.Single(r => r.RoomID.Value == roomId);
ServerAPIRoom = roomManager.ServerSideRooms.Single(r => r.RoomID == roomId);
if (password != ServerAPIRoom.Password.Value)
throw new InvalidOperationException("Invalid password.");

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
@ -17,23 +15,23 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// </summary>
public partial class TestRoomManager : RoomManager
{
public Action<Room, string> JoinRoomRequested;
public Action<Room, string?>? JoinRoomRequested;
private int currentRoomId;
public override void JoinRoom(Room room, string password = null, Action<Room> onSuccess = null, Action<string> onError = null)
public override void JoinRoom(Room room, string? password = null, Action<Room>? onSuccess = null, Action<string>? onError = null)
{
JoinRoomRequested?.Invoke(room, password);
base.JoinRoom(room, password, onSuccess, onError);
}
public void AddRooms(int count, RulesetInfo ruleset = null, bool withPassword = false, bool withSpotlightRooms = false)
public void AddRooms(int count, RulesetInfo? ruleset = null, bool withPassword = false, bool withSpotlightRooms = false)
{
for (int i = 0; i < count; i++)
{
var room = new Room
{
RoomID = { Value = -currentRoomId },
RoomID = -currentRoomId,
Name = { Value = $@"Room {currentRoomId}" },
Host = { Value = new APIUser { Username = @"Host" } },
EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) },

View File

@ -64,7 +64,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
case JoinRoomRequest joinRoomRequest:
{
var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value);
var room = ServerSideRooms.Single(r => r.RoomID == joinRoomRequest.Room.RoomID);
if (joinRoomRequest.Password != room.Password.Value)
{
@ -162,7 +162,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
return true;
case GetRoomRequest getRoomRequest:
getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true));
getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID == getRoomRequest.RoomId), true));
return true;
case CreateRoomScoreRequest createRoomScoreRequest:
@ -261,7 +261,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay
/// <param name="host">The room host.</param>
public void AddServerSideRoom(Room room, APIUser host)
{
room.RoomID.Value ??= currentRoomId++;
room.RoomID ??= currentRoomId++;
room.Host.Value = host;
for (int i = 0; i < room.Playlist.Count; i++)

View File

@ -248,7 +248,7 @@ namespace osu.Game.Users
public InLobby(Room room)
{
RoomID = room.RoomID.Value ?? -1;
RoomID = room.RoomID ?? -1;
RoomName = room.Name.Value;
}