diff --git a/global.json b/global.json deleted file mode 100644 index fe7e453b1cd8..000000000000 --- a/global.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "sdk": { - "version": "10.0.100", - "rollForward": "latestFeature", - "allowPrerelease": false - } -} \ No newline at end of file diff --git a/osu.Android.props b/osu.Android.props index e05709d554b0..28d70c8090b9 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -153,4 +153,20 @@ + + + false + + + + + false + + $(AndroidLinkSkip);Microsoft.CSharp + + + + + + diff --git a/osu.Android/AndroidManifest.xml b/osu.Android/AndroidManifest.xml index 15ab78b1a3e6..f80017f9890c 100644 --- a/osu.Android/AndroidManifest.xml +++ b/osu.Android/AndroidManifest.xml @@ -10,7 +10,7 @@ reaches DispatchKeyEvent and the OS default for root-task activities (moveTaskToBack, i.e. minimise) takes over instead. --> - + diff --git a/osu.Game/Online/Spectator/SpectatorClient.cs b/osu.Game/Online/Spectator/SpectatorClient.cs index 7b62d64b41c1..b7fa2f8cec64 100644 --- a/osu.Game/Online/Spectator/SpectatorClient.cs +++ b/osu.Game/Online/Spectator/SpectatorClient.cs @@ -204,7 +204,10 @@ public void BeginPlaying(long? scoreToken, GameplayState state, Score score) Schedule(() => { if (isPlaying) - throw new InvalidOperationException($"Cannot invoke {nameof(BeginPlaying)} when already playing"); + { + Logger.Log("BeginPlaying called while already playing; ignoring.", LoggingTarget.Network); + return; + } // transfer state at point of beginning play currentState.BeatmapID = score.ScoreInfo.BeatmapInfo!.OnlineID; diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeCarousel.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeCarousel.cs index 89c4c0255b35..e3373decbd1a 100644 --- a/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeCarousel.cs +++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/DailyChallengeCarousel.cs @@ -96,7 +96,7 @@ protected override void Update() if (currentDisplay == lastDisplayed) return; - if (lastDisplayed >= 0) + if (lastDisplayed >= 0 && lastDisplayed < content.Count) { content[lastDisplayed].FadeOutFromOne(250, Easing.OutQuint); navigationFlow[lastDisplayed].Active.Value = false; diff --git a/osu.Game/Screens/OnlinePlay/DailyChallenge/NewDailyChallengeNotification.cs b/osu.Game/Screens/OnlinePlay/DailyChallenge/NewDailyChallengeNotification.cs index 25f1c7465ca3..0bf7ba31e144 100644 --- a/osu.Game/Screens/OnlinePlay/DailyChallenge/NewDailyChallengeNotification.cs +++ b/osu.Game/Screens/OnlinePlay/DailyChallenge/NewDailyChallengeNotification.cs @@ -3,6 +3,7 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Beatmaps.Drawables.Cards; using osu.Game.Configuration; @@ -18,8 +19,6 @@ public partial class NewDailyChallengeNotification : SimpleNotification { private readonly Room room; - private BeatmapCardNano card = null!; - public NewDailyChallengeNotification(Room room) { this.room = room; @@ -30,8 +29,15 @@ private void load(OsuGame? game, SessionStatics statics) { Text = DailyChallengeStrings.ChallengeLiveNotification; var playlistItem = room.Playlist.FirstOrDefault(); + if (playlistItem != null) - Content.Add(card = new BeatmapCardNano((APIBeatmapSet)playlistItem.Beatmap.BeatmapSet!)); + { + Content.Add(new BeatmapCardNano((APIBeatmapSet)playlistItem.Beatmap.BeatmapSet!) + { + RelativeSizeAxes = Axes.X, + }); + } + Activated = () => { if (statics.Get(Static.DailyChallengeIntroPlayed)) @@ -42,11 +48,5 @@ private void load(OsuGame? game, SessionStatics statics) return true; }; } - - protected override void Update() - { - base.Update(); - card.Width = Content.DrawWidth; - } } } diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index a4147b3d3e8d..772b102045e5 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -145,7 +145,7 @@ public void RemoveUser(APIUser user) { Debug.Assert(ServerRoom != null); - ServerRoom.Users.Remove(ServerRoom.Users.Single(u => u.UserID == user.Id)); + ServerRoom.Users.Remove(ServerRoom.Users.First(u => u.UserID == user.Id)); ((IMultiplayerClient)this).UserLeft(clone(new MultiplayerRoomUser(user.Id))); if (ServerRoom.Users.Any()) @@ -165,7 +165,7 @@ public void ChangeUserState(int userId, MultiplayerUserState newState) { Debug.Assert(ServerRoom != null); - var user = ServerRoom.Users.Single(u => u.UserID == userId); + var user = ServerRoom.Users.First(u => u.UserID == userId); user.State = clone(newState); ((IMultiplayerClient)this).UserStateChanged(clone(userId), clone(user.State)); @@ -224,7 +224,7 @@ public void ChangeUserBeatmapAvailability(int userId, BeatmapAvailability newBea { Debug.Assert(ServerRoom != null); - var user = ServerRoom.Users.Single(u => u.UserID == userId); + var user = ServerRoom.Users.First(u => u.UserID == userId); user.BeatmapAvailability = newBeatmapAvailability; ((IMultiplayerClient)this).UserBeatmapAvailabilityChanged(clone(userId), clone(user.BeatmapAvailability)); @@ -238,7 +238,7 @@ protected override async Task JoinRoomInternal(long roomId, str roomId = clone(roomId); password = clone(password); - ServerAPIRoom = ServerSideRooms.Single(r => r.RoomID == roomId); + ServerAPIRoom = ServerSideRooms.First(r => r.RoomID == roomId); if (password != ServerAPIRoom.Password) throw new InvalidOperationException("Invalid password."); @@ -301,7 +301,7 @@ public override Task TransferHost(int userId) Debug.Assert(ServerRoom != null); - ServerRoom.Host = ServerRoom.Users.Single(u => u.UserID == userId); + ServerRoom.Host = ServerRoom.Users.First(u => u.UserID == userId); return ((IMultiplayerClient)this).HostChanged(clone(userId)); } @@ -312,7 +312,7 @@ public override Task KickUser(int userId) Debug.Assert(ServerRoom != null); - var user = ServerRoom.Users.Single(u => u.UserID == userId); + var user = ServerRoom.Users.First(u => u.UserID == userId); ServerRoom.Users.Remove(user); return ((IMultiplayerClient)this).UserKicked(clone(user)); @@ -377,7 +377,7 @@ public void ChangeUserStyle(int userId, int? beatmapId, int? rulesetId) { Debug.Assert(ServerRoom != null); - var user = ServerRoom.Users.Single(u => u.UserID == userId); + var user = ServerRoom.Users.First(u => u.UserID == userId); user.BeatmapId = beatmapId; user.RulesetId = rulesetId; @@ -391,7 +391,7 @@ public void ChangeUserMods(int userId, IEnumerable newMods) { Debug.Assert(ServerRoom != null); - var user = ServerRoom.Users.Single(u => u.UserID == userId); + var user = ServerRoom.Users.First(u => u.UserID == userId); user.Mods = newMods.ToArray(); ((IMultiplayerClient)this).UserModsChanged(clone(userId), clone(user.Mods)); @@ -810,7 +810,7 @@ private async Task updatePlaylistOrder(MultiplayerRoom room) // Also ensure that the API room's playlist is correct. foreach (var item in ServerAPIRoom.Playlist) - item.PlaylistOrder = ServerRoom.Playlist.Single(i => i.ID == item.ID).PlaylistOrder; + item.PlaylistOrder = (ServerRoom.Playlist.FirstOrDefault(i => i.ID == item.ID) ?? new MultiplayerPlaylistItem { ID = item.ID }).PlaylistOrder; } private T clone(T incoming) @@ -818,18 +818,20 @@ private T clone(T incoming) byte[] serialized = MessagePackSerializer.Serialize(typeof(T), incoming, SignalRUnionWorkaroundResolver.OPTIONS); var result = MessagePackSerializer.Deserialize(serialized, SignalRUnionWorkaroundResolver.OPTIONS); - if (incoming is MultiplayerRoomUser { User: { } } sourceUser && result is MultiplayerRoomUser targetUser) targetUser.User = sourceUser.User; - - if (incoming is MultiplayerRoom sourceRoom && result is MultiplayerRoom targetRoom) + if (incoming is MultiplayerRoomUser sourceUser && result is MultiplayerRoomUser targetUser) { - foreach (var user in targetRoom.Users) - user.User = sourceRoom.Users.FirstOrDefault(u => u.UserID == user.UserID)?.User; - - targetRoom.Host?.User = sourceRoom.Host?.User; + targetUser.User = sourceUser.User; } - else if (incoming is MultiplayerRoomUser sourceSingleUser && result is MultiplayerRoomUser targetSingleUser) + else if (incoming is MultiplayerRoom sourceRoom && result is MultiplayerRoom targetRoom) { - targetSingleUser.User = sourceSingleUser.User; + for (int i = 0; i < sourceRoom.Users.Count; i++) + { + if (i < targetRoom.Users.Count) + targetRoom.Users[i].User = sourceRoom.Users[i].User; + } + + if (targetRoom.Host != null && sourceRoom.Host != null) + targetRoom.Host.User = sourceRoom.Host.User; } return result; diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs index 8bbc426c5d2f..4a9cafbf3146 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -9,9 +9,6 @@ using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Rooms; -using osu.Game.Rulesets; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Visual; namespace osu.Game.Tests.Visual.OnlinePlay { @@ -34,16 +31,18 @@ public bool HandleRequest(APIRequest request, APIUser localUser, BeatmapManager { case CreateRoomRequest createRoomRequest: { - var apiRoom = cloneRoom(createRoomRequest.Room); + var apiRoom = createRoomRequest.Room; + var responseRoom = cloneRoom(apiRoom); - // Passwords are explicitly not copied between rooms. - apiRoom.Password = createRoomRequest.Room.Password; + responseRoom.RoomID = currentRoomId++; + responseRoom.Host = localUser; - AddServerSideRoom(apiRoom, localUser); + foreach (var item in responseRoom.Playlist) + { + item.ID = currentPlaylistItemId++; + } - var responseRoom = new APICreatedRoom(); - if (createResponseRoom(apiRoom, false) is Room res) - responseRoom.CopyFrom(res); + ServerSideRooms.Add(responseRoom); // Propagate back to the source room object used by the test. createRoomRequest.Room.RoomID = apiRoom.RoomID; @@ -71,27 +70,6 @@ public bool HandleRequest(APIRequest request, APIUser localUser, BeatmapManager return true; } - case GetRoomsRequest getRoomsRequest: - { - var roomsWithoutParticipants = new List(); - - foreach (var r in ServerSideRooms) - { - if (createResponseRoom(r, false) is Room roomsRes) - roomsWithoutParticipants.Add(roomsRes); - } - - getRoomsRequest.TriggerSuccess(roomsWithoutParticipants); - return true; - } - - case GetRoomRequest getRoomRequest: - { - if (createResponseRoom(ServerSideRooms.FirstOrDefault(r => r.RoomID == getRoomRequest.RoomId), true) is Room getRes) - getRoomRequest.TriggerSuccess(getRes); - return true; - } - case CreateRoomScoreRequest createRoomScoreRequest: createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 }); return true; @@ -159,6 +137,27 @@ public bool HandleRequest(APIRequest request, APIUser localUser, BeatmapManager getBeatmapsRequest.TriggerSuccess(new GetBeatmapsResponse { Beatmaps = createResponseBeatmaps(beatmapManager, getBeatmapsRequest.BeatmapIds.ToArray()) }); return true; } + + case GetRoomsRequest getRoomsRequest: + { + var roomsWithoutParticipants = new List(); + + foreach (var r in ServerSideRooms) + { + if (createResponseRoom(r, false) is Room roomsRes) + roomsWithoutParticipants.Add(roomsRes); + } + + getRoomsRequest.TriggerSuccess(roomsWithoutParticipants); + return true; + } + + case GetRoomRequest getRoomRequest: + { + if (createResponseRoom(ServerSideRooms.FirstOrDefault(r => r.RoomID == getRoomRequest.RoomId), true) is Room getRes) + getRoomRequest.TriggerSuccess(getRes); + return true; + } } return false; @@ -214,12 +213,12 @@ private static List createResponseBeatmaps(BeatmapManager beatmapMan if (baseBeatmap == null) { - baseBeatmap = new TestBeatmap(new RulesetInfo { OnlineID = 0 }).BeatmapInfo; + baseBeatmap = new osu.Game.Tests.Beatmaps.TestBeatmap(new osu.Game.Rulesets.RulesetInfo { OnlineID = 0 }).BeatmapInfo; baseBeatmap.OnlineID = id; baseBeatmap.BeatmapSet!.OnlineID = id; } - result.Add(OsuTestScene.CreateAPIBeatmap(baseBeatmap)); + result.Add(osu.Game.Tests.Visual.OsuTestScene.CreateAPIBeatmap(baseBeatmap)); } return result;