From 27c497145f87449ac17c08796fc57026d3129f2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 16 Dec 2022 18:16:26 +0900 Subject: [PATCH] Fix the MOTHERLOAD of undetected issues that are now visible thanks to net6.0 --- .../Replays/OsuAutoGeneratorBase.cs | 2 +- osu.Game.Tournament/IPC/FileBasedIPC.cs | 2 ++ osu.Game.Tournament/SaveChangesOverlay.cs | 2 +- osu.Game/Audio/SampleInfo.cs | 2 +- osu.Game/Beatmaps/BeatmapImporter.cs | 2 +- .../Beatmaps/BeatmapUpdaterMetadataLookup.cs | 2 +- .../Beatmaps/ControlPoints/ControlPoint.cs | 4 +-- .../ControlPoints/ControlPointGroup.cs | 2 +- osu.Game/Beatmaps/DifficultyRecommender.cs | 6 ++--- .../Configuration/SettingSourceAttribute.cs | 14 +++++------ osu.Game/Database/LegacyImportManager.cs | 8 +++--- osu.Game/Database/Live.cs | 2 +- osu.Game/Database/ModelDownloader.cs | 4 +-- osu.Game/Database/RealmAccess.cs | 4 +-- osu.Game/Extensions/DrawableExtensions.cs | 4 +-- osu.Game/Extensions/TaskExtensions.cs | 2 +- osu.Game/Graphics/UserInterface/OsuTextBox.cs | 2 +- osu.Game/Models/RealmUser.cs | 2 +- osu.Game/Online/API/APIMod.cs | 10 ++++---- .../API/Requests/Responses/APIBeatmap.cs | 2 +- osu.Game/Online/Chat/MessageFormatter.cs | 8 +++--- osu.Game/Online/Chat/MessageNotifier.cs | 5 ++++ .../Online/Metadata/OnlineMetadataClient.cs | 6 ++--- .../Online/Multiplayer/MultiplayerClient.cs | 2 +- .../Online/Multiplayer/MultiplayerRoomUser.cs | 4 +-- .../Multiplayer/OnlineMultiplayerClient.cs | 6 ++--- .../NotificationsClientConnector.cs | 2 +- .../WebSocket/WebSocketNotificationsClient.cs | 25 ++++++++++--------- .../WebSocketNotificationsClientConnector.cs | 2 +- .../PersistentEndpointClientConnector.cs | 6 ++--- ...gnalRDerivedTypeWorkaroundJsonConverter.cs | 3 ++- .../Online/Spectator/OnlineSpectatorClient.cs | 6 ++--- .../Spectator/SpectatorScoreProcessor.cs | 2 +- osu.Game/Overlays/ChatOverlay.cs | 8 ++++-- osu.Game/Overlays/Comments/DrawableComment.cs | 3 +++ osu.Game/Overlays/FirstRunSetupOverlay.cs | 2 +- .../Historical/DrawableMostPlayedBeatmap.cs | 3 --- .../Sections/Ranks/DrawableProfileScore.cs | 3 --- .../Sections/Input/RulesetBindingsSection.cs | 3 --- osu.Game/Rulesets/Mods/IMod.cs | 2 +- osu.Game/Rulesets/Mods/Mod.cs | 20 +++++++-------- osu.Game/Rulesets/Objects/SliderPath.cs | 5 ++++ osu.Game/Rulesets/Ruleset.cs | 2 ++ osu.Game/Rulesets/RulesetInfo.cs | 10 ++++---- osu.Game/Rulesets/RulesetStore.cs | 4 +-- osu.Game/Rulesets/Scoring/HealthProcessor.cs | 2 +- osu.Game/Scoring/ScoreInfo.cs | 2 +- osu.Game/Scoring/ScoreModelDownloader.cs | 2 +- .../Summary/Parts/ControlPointPart.cs | 5 ++++ .../Compose/Components/BlueprintContainer.cs | 4 +++ .../Timeline/TimelineControlPointDisplay.cs | 5 ++++ osu.Game/Screens/Edit/EditorBeatmap.cs | 2 +- .../DrawableRoomParticipantsList.cs | 5 ++++ .../Lounge/Components/RoomsContainer.cs | 5 ++++ .../Spectate/MultiSpectatorScreen.cs | 2 +- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- .../HUD/MultiplayerGameplayLeaderboard.cs | 5 +++- osu.Game/Screens/Play/HUD/SkinnableInfo.cs | 4 +-- .../Screens/Utility/LatencyCertifierScreen.cs | 5 +--- .../Skinning/Editor/SkinComponentToolbox.cs | 5 +--- .../Skinning/GameplaySkinComponentLookup.cs | 2 +- osu.Game/Skinning/LegacySkin.cs | 6 ++--- osu.Game/Skinning/RealmBackedResourceStore.cs | 2 +- osu.Game/Skinning/SkinInfo.cs | 2 +- .../Tests/Beatmaps/BeatmapConversionTest.cs | 2 +- .../Beatmaps/DifficultyCalculatorTest.cs | 2 +- osu.Game/Tests/PollingNotificationsClient.cs | 4 +-- 67 files changed, 165 insertions(+), 130 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs index 1cb3208c30..2f62968029 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGeneratorBase.cs @@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Replays private class ReplayFrameComparer : IComparer { - public int Compare(ReplayFrame f1, ReplayFrame f2) + public int Compare(ReplayFrame? f1, ReplayFrame? f2) { if (f1 == null) throw new ArgumentNullException(nameof(f1)); if (f2 == null) throw new ArgumentNullException(nameof(f2)); diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs index f940571ffe..2d47560947 100644 --- a/osu.Game.Tournament/IPC/FileBasedIPC.cs +++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs @@ -245,8 +245,10 @@ namespace osu.Game.Tournament.IPC { string stableInstallPath; +#pragma warning disable CA1416 using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu")) stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", ""); +#pragma warning restore CA1416 if (ipcFileExistsInDirectory(stableInstallPath)) return stableInstallPath; diff --git a/osu.Game.Tournament/SaveChangesOverlay.cs b/osu.Game.Tournament/SaveChangesOverlay.cs index a81f11cbe1..1bc576bc63 100644 --- a/osu.Game.Tournament/SaveChangesOverlay.cs +++ b/osu.Game.Tournament/SaveChangesOverlay.cs @@ -70,7 +70,7 @@ namespace osu.Game.Tournament private async Task checkForChanges() { - string serialisedLadder = await Task.Run(() => tournamentGame.GetSerialisedLadder()); + string serialisedLadder = await Task.Run(() => tournamentGame.GetSerialisedLadder()).ConfigureAwait(false); // If a save hasn't been triggered by the user yet, populate the initial value lastSerialisedLadder ??= serialisedLadder; diff --git a/osu.Game/Audio/SampleInfo.cs b/osu.Game/Audio/SampleInfo.cs index 19c78f34b2..0191f96825 100644 --- a/osu.Game/Audio/SampleInfo.cs +++ b/osu.Game/Audio/SampleInfo.cs @@ -35,7 +35,7 @@ namespace osu.Game.Audio public bool Equals(SampleInfo? other) => other != null && sampleNames.SequenceEqual(other.sampleNames); - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is SampleInfo other && Equals(other); } } diff --git a/osu.Game/Beatmaps/BeatmapImporter.cs b/osu.Game/Beatmaps/BeatmapImporter.cs index bcb1d7f961..375e0e7aaa 100644 --- a/osu.Game/Beatmaps/BeatmapImporter.cs +++ b/osu.Game/Beatmaps/BeatmapImporter.cs @@ -44,7 +44,7 @@ namespace osu.Game.Beatmaps public override async Task?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original) { - var imported = await Import(notification, importTask); + var imported = await Import(notification, importTask).ConfigureAwait(false); if (!imported.Any()) return null; diff --git a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs index 2fd1d06b7b..71d40b1a48 100644 --- a/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs +++ b/osu.Game/Beatmaps/BeatmapUpdaterMetadataLookup.cs @@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps { try { - await cacheDownloadRequest.PerformAsync(); + await cacheDownloadRequest.PerformAsync().ConfigureAwait(false); } catch { diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 0a09e6e7e6..f46e4af332 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -16,7 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints public void AttachGroup(ControlPointGroup pointGroup) => Time = pointGroup.Time; - public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time); + public int CompareTo(ControlPoint? other) => Time.CompareTo(other?.Time); public virtual Color4 GetRepresentingColour(OsuColour colours) => colours.Yellow; @@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// public ControlPoint DeepClone() { - var copy = (ControlPoint)Activator.CreateInstance(GetType()); + var copy = (ControlPoint)Activator.CreateInstance(GetType())!; copy.CopyFrom(this); diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs index db479f0e5b..1f34f3777d 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointGroup.cs @@ -26,7 +26,7 @@ namespace osu.Game.Beatmaps.ControlPoints Time = time; } - public int CompareTo(ControlPointGroup other) => Time.CompareTo(other.Time); + public int CompareTo(ControlPointGroup? other) => Time.CompareTo(other?.Time); public void Add(ControlPoint point) { diff --git a/osu.Game/Beatmaps/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs index 7a23b32c84..ec00756fd9 100644 --- a/osu.Game/Beatmaps/DifficultyRecommender.cs +++ b/osu.Game/Beatmaps/DifficultyRecommender.cs @@ -51,11 +51,11 @@ namespace osu.Game.Beatmaps if (!recommendedDifficultyMapping.TryGetValue(r, out double recommendation)) continue; - BeatmapInfo beatmapInfo = beatmaps.Where(b => b.Ruleset.ShortName.Equals(r)).OrderBy(b => + BeatmapInfo beatmapInfo = beatmaps.Where(b => b.Ruleset.ShortName.Equals(r, StringComparison.Ordinal)).MinBy(b => { double difference = b.StarRating - recommendation; return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder - }).FirstOrDefault(); + }); if (beatmapInfo != null) return beatmapInfo; @@ -90,7 +90,7 @@ namespace osu.Game.Beatmaps return recommendedDifficultyMapping .OrderByDescending(pair => pair.Value) .Select(pair => pair.Key) - .Where(r => !r.Equals(ruleset.Value.ShortName)) + .Where(r => !r.Equals(ruleset.Value.ShortName, StringComparison.Ordinal)) .Prepend(ruleset.Value.ShortName); } } diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index 043bba3134..1e425c88a6 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -91,15 +91,15 @@ namespace osu.Game.Configuration OrderPosition = orderPosition; } - public int CompareTo(SettingSourceAttribute other) + public int CompareTo(SettingSourceAttribute? other) { - if (OrderPosition == other.OrderPosition) + if (OrderPosition == other?.OrderPosition) return 0; // unordered items come last (are greater than any ordered items). if (OrderPosition == null) return 1; - if (other.OrderPosition == null) + if (other?.OrderPosition == null) return -1; // ordered items are sorted by the order value. @@ -113,7 +113,7 @@ namespace osu.Game.Configuration { foreach (var (attr, property) in obj.GetOrderedSettingsSourceProperties()) { - object value = property.GetValue(obj); + object value = property.GetValue(obj)!; if (attr.SettingControlType != null) { @@ -121,7 +121,7 @@ namespace osu.Game.Configuration if (controlType.EnumerateBaseTypes().All(t => !t.IsGenericType || t.GetGenericTypeDefinition() != typeof(SettingsItem<>))) throw new InvalidOperationException($"{nameof(SettingSourceAttribute)} had an unsupported custom control type ({controlType.ReadableName()})"); - var control = (Drawable)Activator.CreateInstance(controlType); + var control = (Drawable)Activator.CreateInstance(controlType)!; controlType.GetProperty(nameof(SettingsItem.SettingSourceObject))?.SetValue(control, obj); controlType.GetProperty(nameof(SettingsItem.LabelText))?.SetValue(control, attr.Label); controlType.GetProperty(nameof(SettingsItem.TooltipText))?.SetValue(control, attr.Description); @@ -188,7 +188,7 @@ namespace osu.Game.Configuration case IBindable bindable: var dropdownType = typeof(ModSettingsEnumDropdown<>).MakeGenericType(bindable.GetType().GetGenericArguments()[0]); - var dropdown = (Drawable)Activator.CreateInstance(dropdownType); + var dropdown = (Drawable)Activator.CreateInstance(dropdownType)!; dropdownType.GetProperty(nameof(SettingsDropdown.LabelText))?.SetValue(dropdown, attr.Label); dropdownType.GetProperty(nameof(SettingsDropdown.TooltipText))?.SetValue(dropdown, attr.Description); @@ -231,7 +231,7 @@ namespace osu.Game.Configuration // An unknown (e.g. enum) generic type. var valueMethod = u.GetType().GetProperty(nameof(IBindable.Value)); Debug.Assert(valueMethod != null); - return valueMethod.GetValue(u); + return valueMethod.GetValue(u)!; default: // fall back for non-bindable cases. diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs index b5338fbe1f..5c01107f01 100644 --- a/osu.Game/Database/LegacyImportManager.cs +++ b/osu.Game/Database/LegacyImportManager.cs @@ -66,16 +66,16 @@ namespace osu.Game.Database switch (content) { case StableContent.Beatmaps: - return await new LegacyBeatmapImporter(beatmaps).GetAvailableCount(stableStorage); + return await new LegacyBeatmapImporter(beatmaps).GetAvailableCount(stableStorage).ConfigureAwait(false); case StableContent.Skins: - return await new LegacySkinImporter(skins).GetAvailableCount(stableStorage); + return await new LegacySkinImporter(skins).GetAvailableCount(stableStorage).ConfigureAwait(false); case StableContent.Collections: - return await new LegacyCollectionImporter(realmAccess).GetAvailableCount(stableStorage); + return await new LegacyCollectionImporter(realmAccess).GetAvailableCount(stableStorage).ConfigureAwait(false); case StableContent.Scores: - return await new LegacyScoreImporter(scores).GetAvailableCount(stableStorage); + return await new LegacyScoreImporter(scores).GetAvailableCount(stableStorage).ConfigureAwait(false); default: throw new ArgumentException($"Only one {nameof(StableContent)} flag should be specified."); diff --git a/osu.Game/Database/Live.cs b/osu.Game/Database/Live.cs index 3bb11c3a50..2df6f3f508 100644 --- a/osu.Game/Database/Live.cs +++ b/osu.Game/Database/Live.cs @@ -61,6 +61,6 @@ namespace osu.Game.Database public override int GetHashCode() => HashCode.Combine(ID); - public override string ToString() => PerformRead(i => i.ToString()); + public override string? ToString() => PerformRead(i => i.ToString()); } } diff --git a/osu.Game/Database/ModelDownloader.cs b/osu.Game/Database/ModelDownloader.cs index 3e2d034937..a09d637c9d 100644 --- a/osu.Game/Database/ModelDownloader.cs +++ b/osu.Game/Database/ModelDownloader.cs @@ -71,9 +71,9 @@ namespace osu.Game.Database bool importSuccessful; if (originalModel != null) - importSuccessful = (await importer.ImportAsUpdate(notification, new ImportTask(filename), originalModel)) != null; + importSuccessful = (await importer.ImportAsUpdate(notification, new ImportTask(filename), originalModel).ConfigureAwait(false)) != null; else - importSuccessful = (await importer.Import(notification, new ImportTask(filename))).Any(); + importSuccessful = (await importer.Import(notification, new ImportTask(filename)).ConfigureAwait(false)).Any(); // for now a failed import will be marked as a failed download for simplicity. if (!importSuccessful) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 1a938c12e5..177c671bca 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -481,7 +481,7 @@ namespace osu.Game.Database // server, which we don't use. May want to report upstream or revisit in the future. using (var realm = getRealmInstance()) // ReSharper disable once AccessToDisposedClosure (WriteAsync should be marked as [InstantHandle]). - await realm.WriteAsync(() => action(realm)); + await realm.WriteAsync(() => action(realm)).ConfigureAwait(false); pendingAsyncWrites.Signal(); }); @@ -558,7 +558,7 @@ namespace osu.Game.Database return new InvokeOnDisposal(() => model.PropertyChanged -= onPropertyChanged); - void onPropertyChanged(object sender, PropertyChangedEventArgs args) + void onPropertyChanged(object? sender, PropertyChangedEventArgs args) { if (args.PropertyName == propertyName) onChanged(propLookupCompiled(model)); diff --git a/osu.Game/Extensions/DrawableExtensions.cs b/osu.Game/Extensions/DrawableExtensions.cs index 35f2d61437..65b9e46764 100644 --- a/osu.Game/Extensions/DrawableExtensions.cs +++ b/osu.Game/Extensions/DrawableExtensions.cs @@ -66,10 +66,10 @@ namespace osu.Game.Extensions foreach (var (_, property) in component.GetSettingsSourceProperties()) { - if (!info.Settings.TryGetValue(property.Name.ToSnakeCase(), out object settingValue)) + if (!info.Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) continue; - skinnable.CopyAdjustedSetting((IBindable)property.GetValue(component), settingValue); + skinnable.CopyAdjustedSetting(((IBindable)property.GetValue(component)!), settingValue); } } diff --git a/osu.Game/Extensions/TaskExtensions.cs b/osu.Game/Extensions/TaskExtensions.cs index b4a0c02e35..43abb59042 100644 --- a/osu.Game/Extensions/TaskExtensions.cs +++ b/osu.Game/Extensions/TaskExtensions.cs @@ -37,7 +37,7 @@ namespace osu.Game.Extensions if (cancellationToken.IsCancellationRequested) { - tcs.SetCanceled(); + tcs.SetCanceled(cancellationToken); } else { diff --git a/osu.Game/Graphics/UserInterface/OsuTextBox.cs b/osu.Game/Graphics/UserInterface/OsuTextBox.cs index 1114c29afd..a65204e6b3 100644 --- a/osu.Game/Graphics/UserInterface/OsuTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTextBox.cs @@ -277,7 +277,7 @@ namespace osu.Game.Graphics.UserInterface { var samples = sampleMap[feedbackSampleType]; - if (samples == null || samples.Length == 0) + if (samples.Length == 0) return null; return samples[RNG.Next(0, samples.Length)]?.GetChannel(); diff --git a/osu.Game/Models/RealmUser.cs b/osu.Game/Models/RealmUser.cs index e20ffc0808..6997f04f44 100644 --- a/osu.Game/Models/RealmUser.cs +++ b/osu.Game/Models/RealmUser.cs @@ -27,7 +27,7 @@ namespace osu.Game.Models public bool IsBot => false; - public bool Equals(RealmUser other) + public bool Equals(RealmUser? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 176f10975d..45128375ab 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -39,7 +39,7 @@ namespace osu.Game.Online.API foreach (var (_, property) in mod.GetSettingsSourceProperties()) { - var bindable = (IBindable)property.GetValue(mod); + var bindable = (IBindable)property.GetValue(mod)!; if (!bindable.IsDefault) Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue()); @@ -60,16 +60,16 @@ namespace osu.Game.Online.API { foreach (var (_, property) in resultMod.GetSettingsSourceProperties()) { - if (!Settings.TryGetValue(property.Name.ToSnakeCase(), out object settingValue)) + if (!Settings.TryGetValue(property.Name.ToSnakeCase(), out object? settingValue)) continue; try { - resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod), settingValue); + resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod)!, settingValue); } catch (Exception ex) { - Logger.Log($"Failed to copy mod setting value '{settingValue ?? "null"}' to \"{property.Name}\": {ex.Message}"); + Logger.Log($"Failed to copy mod setting value '{settingValue}' to \"{property.Name}\": {ex.Message}"); } } } @@ -79,7 +79,7 @@ namespace osu.Game.Online.API public bool ShouldSerializeSettings() => Settings.Count > 0; - public bool Equals(APIMod other) + public bool Equals(APIMod? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 8a77801c3a..27ad2a746c 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -143,7 +143,7 @@ namespace osu.Game.Online.API.Requests.Responses public bool Equals(IRulesetInfo? other) => other is APIRuleset r && this.MatchesOnlineID(r); - public int CompareTo(IRulesetInfo other) + public int CompareTo(IRulesetInfo? other) { if (!(other is APIRuleset ruleset)) throw new ArgumentException($@"Object is not of type {nameof(APIRuleset)}.", nameof(other)); diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index 7a040d9446..b9bca9dc20 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -71,7 +71,7 @@ namespace osu.Game.Online.Chat { int index = m.Index - captureOffset; - string? displayText = string.Format(display, + string displayText = string.Format(display, m.Groups[0], m.Groups["text"].Value, m.Groups["url"].Value).Trim(); @@ -109,7 +109,7 @@ namespace osu.Game.Online.Chat foreach (Match m in regex.Matches(result.Text, startIndex)) { int index = m.Index; - string? linkText = m.Groups["link"].Value; + string linkText = m.Groups["link"].Value; int indexLength = linkText.Length; var details = GetLinkDetails(linkText); @@ -125,7 +125,7 @@ namespace osu.Game.Online.Chat public static LinkDetails GetLinkDetails(string url) { - string[]? args = url.Split('/', StringSplitOptions.RemoveEmptyEntries); + string[] args = url.Split('/', StringSplitOptions.RemoveEmptyEntries); args[0] = args[0].TrimEnd(':'); switch (args[0]) @@ -362,6 +362,6 @@ namespace osu.Game.Online.Chat public bool Overlaps(Link otherLink) => Index < otherLink.Index + otherLink.Length && otherLink.Index < Index + Length; - public int CompareTo(Link otherLink) => Index > otherLink.Index ? 1 : -1; + public int CompareTo(Link? otherLink) => Index > otherLink?.Index ? 1 : -1; } } diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 4872d93467..9b2ad666b2 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using System.Text.RegularExpressions; using osu.Framework.Allocation; @@ -61,12 +62,16 @@ namespace osu.Game.Online.Chat switch (e.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(e.NewItems != null); + foreach (var channel in e.NewItems.Cast()) channel.NewMessagesArrived += checkNewMessages; break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(e.OldItems != null); + foreach (var channel in e.OldItems.Cast()) channel.NewMessagesArrived -= checkNewMessages; diff --git a/osu.Game/Online/Metadata/OnlineMetadataClient.cs b/osu.Game/Online/Metadata/OnlineMetadataClient.cs index ba7ccb24f7..57311419f7 100644 --- a/osu.Game/Online/Metadata/OnlineMetadataClient.cs +++ b/osu.Game/Online/Metadata/OnlineMetadataClient.cs @@ -68,7 +68,7 @@ namespace osu.Game.Online.Metadata while (true) { Logger.Log($"Requesting catch-up from {lastQueueId.Value}"); - var catchUpChanges = await GetChangesSince(lastQueueId.Value); + var catchUpChanges = await GetChangesSince(lastQueueId.Value).ConfigureAwait(true); lastQueueId.Value = catchUpChanges.LastProcessedQueueID; @@ -78,7 +78,7 @@ namespace osu.Game.Online.Metadata break; } - await ProcessChanges(catchUpChanges.BeatmapSetIDs); + await ProcessChanges(catchUpChanges.BeatmapSetIDs).ConfigureAwait(true); } } catch (Exception e) @@ -101,7 +101,7 @@ namespace osu.Game.Online.Metadata if (!catchingUp) lastQueueId.Value = updates.LastProcessedQueueID; - await ProcessChanges(updates.BeatmapSetIDs); + await ProcessChanges(updates.BeatmapSetIDs).ConfigureAwait(false); } public override Task GetChangesSince(int queueId) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index bd87f2d43e..2be7327234 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -822,7 +822,7 @@ namespace osu.Game.Online.Multiplayer { if (cancellationToken.IsCancellationRequested) { - tcs.SetCanceled(); + tcs.SetCanceled(cancellationToken); return; } diff --git a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs index 681a839b89..d70a2797c4 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerRoomUser.cs @@ -54,10 +54,10 @@ namespace osu.Game.Online.Multiplayer return UserID == other.UserID; } - public override bool Equals(object obj) + public override bool Equals(object? obj) { if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; + if (obj?.GetType() != GetType()) return false; return Equals((MultiplayerRoomUser)obj); } diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 386a3d5262..8ff0ce4065 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -80,7 +80,7 @@ namespace osu.Game.Online.Multiplayer try { - return await connection.InvokeAsync(nameof(IMultiplayerServer.JoinRoomWithPassword), roomId, password ?? string.Empty); + return await connection.InvokeAsync(nameof(IMultiplayerServer.JoinRoomWithPassword), roomId, password ?? string.Empty).ConfigureAwait(false); } catch (HubException exception) { @@ -88,8 +88,8 @@ namespace osu.Game.Online.Multiplayer { Debug.Assert(connector != null); - await connector.Reconnect(); - return await JoinRoom(roomId, password); + await connector.Reconnect().ConfigureAwait(false); + return await JoinRoom(roomId, password).ConfigureAwait(false); } throw; diff --git a/osu.Game/Online/Notifications/NotificationsClientConnector.cs b/osu.Game/Online/Notifications/NotificationsClientConnector.cs index d2c2e6673c..34ce186cb8 100644 --- a/osu.Game/Online/Notifications/NotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/NotificationsClientConnector.cs @@ -27,7 +27,7 @@ namespace osu.Game.Online.Notifications protected sealed override async Task BuildConnectionAsync(CancellationToken cancellationToken) { - var client = await BuildNotificationClientAsync(cancellationToken); + var client = await BuildNotificationClientAsync(cancellationToken).ConfigureAwait(false); client.ChannelJoined = c => ChannelJoined?.Invoke(c); client.ChannelParted = c => ChannelParted?.Invoke(c); diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index d8d78297e3..73e5dcec6f 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Concurrent; using System.Diagnostics; +using System.Net; using System.Net.WebSockets; using System.Text; using System.Threading; @@ -36,11 +37,11 @@ namespace osu.Game.Online.Notifications.WebSocket public override async Task ConnectAsync(CancellationToken cancellationToken) { await socket.ConnectAsync(new Uri(endpoint), cancellationToken).ConfigureAwait(false); - await sendMessage(new StartChatRequest(), CancellationToken.None); + await sendMessage(new StartChatRequest(), CancellationToken.None).ConfigureAwait(false); runReadLoop(cancellationToken); - await base.ConnectAsync(cancellationToken); + await base.ConnectAsync(cancellationToken).ConfigureAwait(false); } private void runReadLoop(CancellationToken cancellationToken) => Task.Run(async () => @@ -52,7 +53,7 @@ namespace osu.Game.Online.Notifications.WebSocket { try { - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken); + WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); switch (result.MessageType) { @@ -72,7 +73,7 @@ namespace osu.Game.Online.Notifications.WebSocket break; } - await onMessageReceivedAsync(message); + await onMessageReceivedAsync(message).ConfigureAwait(false); } break; @@ -81,12 +82,12 @@ namespace osu.Game.Online.Notifications.WebSocket throw new NotImplementedException("Binary message type not supported."); case WebSocketMessageType.Close: - throw new Exception("Connection closed by remote host."); + throw new WebException("Connection closed by remote host."); } } catch (Exception ex) { - await InvokeClosed(ex); + await InvokeClosed(ex).ConfigureAwait(false); return; } } @@ -109,7 +110,7 @@ namespace osu.Game.Online.Notifications.WebSocket if (socket.State != WebSocketState.Open) return; - await socket.SendAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)), WebSocketMessageType.Text, true, cancellationToken); + await socket.SendAsync(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message)), WebSocketMessageType.Text, true, cancellationToken).ConfigureAwait(false); } private async Task onMessageReceivedAsync(SocketMessage message) @@ -141,7 +142,7 @@ namespace osu.Game.Online.Notifications.WebSocket Debug.Assert(messageData != null); foreach (var msg in messageData.Messages) - HandleChannelJoined(await getChannel(msg.ChannelId)); + HandleChannelJoined(await getChannel(msg.ChannelId).ConfigureAwait(false)); HandleMessages(messageData.Messages); break; @@ -150,7 +151,7 @@ namespace osu.Game.Online.Notifications.WebSocket private async Task getChannel(long channelId) { - if (channelsMap.TryGetValue(channelId, out Channel channel)) + if (channelsMap.TryGetValue(channelId, out Channel? channel)) return channel; var tsc = new TaskCompletionSource(); @@ -166,13 +167,13 @@ namespace osu.Game.Online.Notifications.WebSocket API.Queue(req); - return await tsc.Task; + return await tsc.Task.ConfigureAwait(false); } public override async ValueTask DisposeAsync() { - await base.DisposeAsync(); - await closeAsync(); + await base.DisposeAsync().ConfigureAwait(false); + await closeAsync().ConfigureAwait(false); socket.Dispose(); } } diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs index 21335a3b59..f50369a06c 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs @@ -32,7 +32,7 @@ namespace osu.Game.Online.Notifications.WebSocket req.Failure += ex => tcs.SetException(ex); api.Queue(req); - string endpoint = await tcs.Task; + string endpoint = await tcs.Task.ConfigureAwait(false); ClientWebSocket socket = new ClientWebSocket(); socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}"); diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 55e9190f99..e33924047d 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -65,11 +65,11 @@ namespace osu.Game.Online { case APIState.Failing: case APIState.Offline: - await disconnect(true); + await disconnect(true).ConfigureAwait(true); break; case APIState.Online: - await connect(); + await connect().ConfigureAwait(true); break; } } @@ -147,7 +147,7 @@ namespace osu.Game.Online { bool hasBeenCancelled = cancellationToken.IsCancellationRequested; - await disconnect(true); + await disconnect(true).ConfigureAwait(false); if (ex != null) await handleErrorAndDelay(ex, CancellationToken.None).ConfigureAwait(false); diff --git a/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs b/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs index a999cb47f8..86708bee82 100644 --- a/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs +++ b/osu.Game/Online/SignalRDerivedTypeWorkaroundJsonConverter.cs @@ -33,7 +33,8 @@ namespace osu.Game.Online object? instance = Activator.CreateInstance(resolvedType); - jsonSerializer.Populate(obj["$value"]!.CreateReader(), instance); + if (instance != null) + jsonSerializer.Populate(obj["$value"]!.CreateReader(), instance); return instance; } diff --git a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs index d5c1e56761..01b775549e 100644 --- a/osu.Game/Online/Spectator/OnlineSpectatorClient.cs +++ b/osu.Game/Online/Spectator/OnlineSpectatorClient.cs @@ -56,7 +56,7 @@ namespace osu.Game.Online.Spectator try { - await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), scoreToken, state); + await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), scoreToken, state).ConfigureAwait(false); } catch (Exception exception) { @@ -64,8 +64,8 @@ namespace osu.Game.Online.Spectator { Debug.Assert(connector != null); - await connector.Reconnect(); - await BeginPlayingInternal(scoreToken, state); + await connector.Reconnect().ConfigureAwait(false); + await BeginPlayingInternal(scoreToken, state).ConfigureAwait(false); } // Exceptions can occur if, for instance, the locally played beatmap doesn't have a server-side counterpart. diff --git a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs index 75b6a6e83b..1c505ea107 100644 --- a/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs +++ b/osu.Game/Online/Spectator/SpectatorScoreProcessor.cs @@ -184,7 +184,7 @@ namespace osu.Game.Online.Spectator Header = header; } - public int CompareTo(TimedFrame other) => Time.CompareTo(other.Time); + public int CompareTo(TimedFrame? other) => Time.CompareTo(other?.Time); } } } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 98e153108f..c539cdc5ec 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -352,11 +352,13 @@ namespace osu.Game.Overlays protected virtual DrawableChannel CreateDrawableChannel(Channel newChannel) => new DrawableChannel(newChannel); - private void joinedChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) + private void joinedChannelsChanged(object? sender, NotifyCollectionChangedEventArgs args) { switch (args.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + IEnumerable newChannels = args.NewItems.OfType().Where(isChatChannel); foreach (var channel in newChannels) @@ -365,6 +367,8 @@ namespace osu.Game.Overlays break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(args.OldItems != null); + IEnumerable leftChannels = args.OldItems.OfType().Where(isChatChannel); foreach (var channel in leftChannels) @@ -384,7 +388,7 @@ namespace osu.Game.Overlays } } - private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) + private void availableChannelsChanged(object? sender, NotifyCollectionChangedEventArgs args) => channelListing.UpdateAvailableChannels(channelManager.AvailableChannels); private void handleChatMessage(string message) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 7bada5ef2a..a1ef998beb 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -19,6 +19,7 @@ using System; using osu.Framework.Graphics.Shapes; using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; +using System.Diagnostics; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Graphics.UserInterface; @@ -359,6 +360,8 @@ namespace osu.Game.Overlays.Comments switch (args.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + onRepliesAdded(args.NewItems.Cast()); break; diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 45fc9d27ea..f2fdaefbb4 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -301,7 +301,7 @@ namespace osu.Game.Overlays if (currentStepIndex < steps.Count) { - var nextScreen = (Screen)Activator.CreateInstance(steps[currentStepIndex.Value]); + var nextScreen = (Screen)Activator.CreateInstance(steps[currentStepIndex.Value])!; loadingShowDelegate = Scheduler.AddDelayed(() => loading.Show(), 200); nextScreen.OnLoadComplete += _ => diff --git a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs index 414c6f194a..a31ee88f3b 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/DrawableMostPlayedBeatmap.cs @@ -3,7 +3,6 @@ #nullable disable -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -131,8 +130,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical { var metadata = beatmapInfo.Metadata; - Debug.Assert(metadata != null); - return new Drawable[] { new OsuSpriteText diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs index f1f3ecd4fb..67df4825cc 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileScore.cs @@ -4,7 +4,6 @@ #nullable disable using System; -using System.Diagnostics; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -269,8 +268,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks { var metadata = beatmapInfo.Metadata; - Debug.Assert(metadata != null); - return new Drawable[] { new OsuSpriteText diff --git a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs index dcdb15fc19..19f0d0f7d1 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs @@ -3,7 +3,6 @@ #nullable disable -using System.Diagnostics; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; @@ -29,8 +28,6 @@ namespace osu.Game.Overlays.Settings.Sections.Input var r = ruleset.CreateInstance(); - Debug.Assert(r != null); - foreach (int variant in r.AvailableVariants) Add(new VariantBindingsSubsection(ruleset, variant)); } diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs index 1f9e26c9d7..05b2510e53 100644 --- a/osu.Game/Rulesets/Mods/IMod.cs +++ b/osu.Game/Rulesets/Mods/IMod.cs @@ -55,6 +55,6 @@ namespace osu.Game.Rulesets.Mods /// /// Create a fresh instance based on this mod. /// - Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType()); + Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType())!; } } diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 98df540de4..04d55bc5fe 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mods foreach ((SettingSourceAttribute attr, PropertyInfo property) in this.GetOrderedSettingsSourceProperties()) { - var bindable = (IBindable)property.GetValue(this); + var bindable = (IBindable)property.GetValue(this)!; if (!bindable.IsDefault) tooltipTexts.Add($"{attr.Label} {bindable}"); @@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Mods /// public virtual Mod DeepClone() { - var result = (Mod)Activator.CreateInstance(GetType()); + var result = (Mod)Activator.CreateInstance(GetType())!; result.CopyFrom(this); return result; } @@ -150,8 +150,8 @@ namespace osu.Game.Rulesets.Mods foreach (var (_, prop) in this.GetSettingsSourceProperties()) { - var targetBindable = (IBindable)prop.GetValue(this); - var sourceBindable = (IBindable)prop.GetValue(source); + var targetBindable = (IBindable)prop.GetValue(this)!; + var sourceBindable = (IBindable)prop.GetValue(source)!; CopyAdjustedSetting(targetBindable, sourceBindable); } @@ -183,9 +183,9 @@ namespace osu.Game.Rulesets.Mods } } - public bool Equals(IMod other) => other is Mod them && Equals(them); + public bool Equals(IMod? other) => other is Mod them && Equals(them); - public bool Equals(Mod other) + public bool Equals(Mod? other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; @@ -209,16 +209,16 @@ namespace osu.Game.Rulesets.Mods /// /// Reset all custom settings for this mod back to their defaults. /// - public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType())); + public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType())!); private class ModSettingsEqualityComparer : IEqualityComparer { public static ModSettingsEqualityComparer Default { get; } = new ModSettingsEqualityComparer(); - public bool Equals(IBindable x, IBindable y) + public bool Equals(IBindable? x, IBindable? y) { - object xValue = x.GetUnderlyingSettingValue(); - object yValue = y.GetUnderlyingSettingValue(); + object? xValue = x?.GetUnderlyingSettingValue(); + object? yValue = y?.GetUnderlyingSettingValue(); return EqualityComparer.Default.Equals(xValue, yValue); } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index ddc121eb5b..c9d2928dc3 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using Newtonsoft.Json; using osu.Framework.Bindables; @@ -57,12 +58,16 @@ namespace osu.Game.Rulesets.Objects switch (args.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + foreach (var c in args.NewItems.Cast()) c.Changed += invalidate; break; case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Remove: + Debug.Assert(args.OldItems != null); + foreach (var c in args.OldItems.Cast()) c.Changed -= invalidate; break; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index a446210c8a..a73151362b 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -89,6 +89,8 @@ namespace osu.Game.Rulesets // Confine all mods of each mod type into a single IEnumerable .SelectMany(GetModsFor) // Filter out all null mods + // This is to handle old rulesets which were doing mods bad. Can be removed at some point we are sure nulls will not appear here. + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract .Where(mod => mod != null) // Resolve MultiMods as their .Mods property .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); diff --git a/osu.Game/Rulesets/RulesetInfo.cs b/osu.Game/Rulesets/RulesetInfo.cs index 91954320a4..6a4e0f0b48 100644 --- a/osu.Game/Rulesets/RulesetInfo.cs +++ b/osu.Game/Rulesets/RulesetInfo.cs @@ -53,21 +53,21 @@ namespace osu.Game.Rulesets public bool Equals(IRulesetInfo? other) => other is RulesetInfo r && Equals(r); - public int CompareTo(RulesetInfo other) + public int CompareTo(RulesetInfo? other) { - if (OnlineID >= 0 && other.OnlineID >= 0) + if (OnlineID >= 0 && other?.OnlineID >= 0) return OnlineID.CompareTo(other.OnlineID); // Official rulesets are always given precedence for the time being. if (OnlineID >= 0) return -1; - if (other.OnlineID >= 0) + if (other?.OnlineID >= 0) return 1; - return string.Compare(ShortName, other.ShortName, StringComparison.Ordinal); + return string.Compare(ShortName, other?.ShortName, StringComparison.Ordinal); } - public int CompareTo(IRulesetInfo other) + public int CompareTo(IRulesetInfo? other) { if (!(other is RulesetInfo ruleset)) throw new ArgumentException($@"Object is not of type {nameof(RulesetInfo)}.", nameof(other)); diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index e2b8cd2c4e..adebbe6181 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets private void loadRulesetFromFile(string file) { - string? filename = Path.GetFileNameWithoutExtension(file); + string filename = Path.GetFileNameWithoutExtension(file); if (LoadedAssemblies.Values.Any(t => Path.GetFileNameWithoutExtension(t.Assembly.Location) == filename)) return; @@ -158,7 +158,7 @@ namespace osu.Game.Rulesets } catch (Exception e) { - LogFailedLoad(assembly.GetName().Name.Split('.').Last(), e); + LogFailedLoad(assembly.GetName().Name!.Split('.').Last(), e); } } diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs index cdfe71943e..b70ddd5e24 100644 --- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs +++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs @@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Scoring { foreach (var condition in FailConditions.GetInvocationList()) { - bool conditionResult = (bool)condition.Method.Invoke(condition.Target, new object[] { this, result }); + bool conditionResult = (bool)condition.Method.Invoke(condition.Target, new object[] { this, result })!; if (conditionResult) return true; } diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs index a9ced62c95..1009474d89 100644 --- a/osu.Game/Scoring/ScoreInfo.cs +++ b/osu.Game/Scoring/ScoreInfo.cs @@ -317,7 +317,7 @@ namespace osu.Game.Scoring #endregion - public bool Equals(ScoreInfo other) => other.ID == ID; + public bool Equals(ScoreInfo? other) => other?.ID == ID; public override string ToString() => this.GetDisplayTitle(); } diff --git a/osu.Game/Scoring/ScoreModelDownloader.cs b/osu.Game/Scoring/ScoreModelDownloader.cs index 514b7a57de..c5434e8faf 100644 --- a/osu.Game/Scoring/ScoreModelDownloader.cs +++ b/osu.Game/Scoring/ScoreModelDownloader.cs @@ -17,7 +17,7 @@ namespace osu.Game.Scoring protected override ArchiveDownloadRequest CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score); - public override ArchiveDownloadRequest GetExistingDownload(IScoreInfo model) + public override ArchiveDownloadRequest? GetExistingDownload(IScoreInfo model) => CurrentDownloads.Find(r => r.Model.MatchesOnlineID(model)); } } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs index 2d26e6f90b..111ba0b732 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/ControlPointPart.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Game.Beatmaps.ControlPoints; @@ -33,6 +34,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts break; case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + foreach (var group in args.NewItems.OfType()) { // as an optimisation, don't add a visualisation if there are already groups with the same types in close proximity. @@ -47,6 +50,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(args.OldItems != null); + foreach (var group in args.OldItems.OfType()) { var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group)); diff --git a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs index 60fec5bcc6..77892f21e6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/BlueprintContainer.cs @@ -58,6 +58,8 @@ namespace osu.Game.Screens.Edit.Compose.Components switch (args.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + foreach (object o in args.NewItems) { if (blueprintMap.TryGetValue((T)o, out var blueprint)) @@ -67,6 +69,8 @@ namespace osu.Game.Screens.Edit.Compose.Components break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(args.OldItems != null); + foreach (object o in args.OldItems) { if (blueprintMap.TryGetValue((T)o, out var blueprint)) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs index 9783c4184a..29983c9cbf 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineControlPointDisplay.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using osu.Framework.Bindables; using osu.Game.Beatmaps.ControlPoints; @@ -33,11 +34,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline break; case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + foreach (var group in args.NewItems.OfType()) Add(new TimelineControlPointGroup(group)); break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(args.OldItems != null); + foreach (var group in args.OldItems.OfType()) { var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group)); diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index e204b44db3..1554bf1bb1 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -304,7 +304,7 @@ namespace osu.Game.Screens.Edit /// The index of the to remove. public void RemoveAt(int index) { - var hitObject = (HitObject)mutableHitObjects[index]; + HitObject hitObject = (HitObject)mutableHitObjects[index]!; mutableHitObjects.RemoveAt(index); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs index 3b66355dab..c31633eefc 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoomParticipantsList.cs @@ -4,6 +4,7 @@ #nullable disable using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -197,11 +198,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components switch (e.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(e.NewItems != null); + foreach (var added in e.NewItems.OfType()) addUser(added); break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(e.OldItems != null); + foreach (var removed in e.OldItems.OfType()) removeUser(removed); break; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index e723dfe3e6..ac6403bb34 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -117,10 +118,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components switch (args.Action) { case NotifyCollectionChangedAction.Add: + Debug.Assert(args.NewItems != null); + addRooms(args.NewItems.Cast()); break; case NotifyCollectionChangedAction.Remove: + Debug.Assert(args.OldItems != null); + removeRooms(args.OldItems.Cast()); break; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index fe27e2cf20..33ca806696 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// /// Whether all spectating players have finished loading. /// - public bool AllPlayersLoaded => instances.All(p => p?.PlayerLoaded == true); + public bool AllPlayersLoaded => instances.All(p => p.PlayerLoaded); protected override UserActivity InitialActivity => new UserActivity.SpectatingMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 50a9992f4f..e93f56c2e2 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -349,7 +349,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists public void SelectBeatmap() => editPlaylistButton.TriggerClick(); - private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => + private void onPlaylistChanged(object? sender, NotifyCollectionChangedEventArgs e) => playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}"; private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0; diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 2743173a6d..620f3718c2 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using System.Threading; using osu.Framework.Allocation; @@ -153,11 +154,13 @@ namespace osu.Game.Screens.Play.HUD } } - private void playingUsersChanged(object sender, NotifyCollectionChangedEventArgs e) + private void playingUsersChanged(object? sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Remove: + Debug.Assert(e.OldItems != null); + foreach (int userId in e.OldItems.OfType()) { spectatorClient.StopWatchingUser(userId); diff --git a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs index 6d63776dbb..da759b4329 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs @@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play.HUD foreach (var (_, property) in component.GetSettingsSourceProperties()) { - var bindable = (IBindable)property.GetValue(component); + var bindable = (IBindable)property.GetValue(component)!; if (!bindable.IsDefault) Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue()); @@ -88,7 +88,7 @@ namespace osu.Game.Screens.Play.HUD { try { - Drawable d = (Drawable)Activator.CreateInstance(Type); + Drawable d = (Drawable)Activator.CreateInstance(Type)!; d.ApplySkinnableInfo(this); return d; } diff --git a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs index 8ff6d3cf4f..212cebeaf5 100644 --- a/osu.Game/Screens/Utility/LatencyCertifierScreen.cs +++ b/osu.Game/Screens/Utility/LatencyCertifierScreen.cs @@ -259,10 +259,7 @@ namespace osu.Game.Screens.Utility var displayMode = host.Window?.CurrentDisplayMode.Value; - string exclusive = "unknown"; - - if (host.Renderer is IWindowsRenderer windowsRenderer) - exclusive = windowsRenderer.FullscreenCapability.ToString(); + string exclusive = (host.Renderer as IWindowsRenderer)?.FullscreenCapability.ToString() ?? "unknown"; statusText.Clear(); diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 68ac84df48..053119557f 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -59,9 +58,7 @@ namespace osu.Game.Skinning.Editor { try { - var instance = (Drawable)Activator.CreateInstance(type); - - Debug.Assert(instance != null); + Drawable instance = (Drawable)Activator.CreateInstance(type)!; if (!((ISkinnableDrawable)instance).IsEditable) return; diff --git a/osu.Game/Skinning/GameplaySkinComponentLookup.cs b/osu.Game/Skinning/GameplaySkinComponentLookup.cs index 2d1dec4691..9247ca0e4d 100644 --- a/osu.Game/Skinning/GameplaySkinComponentLookup.cs +++ b/osu.Game/Skinning/GameplaySkinComponentLookup.cs @@ -16,7 +16,7 @@ namespace osu.Game.Skinning } protected virtual string RulesetPrefix => string.Empty; - protected virtual string ComponentName => Component.ToString(); + protected virtual string ComponentName => Component.ToString() ?? string.Empty; public string LookupName => string.Join('/', new[] { "Gameplay", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s))); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index ea223d172d..5f12d2ce23 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -105,7 +105,7 @@ namespace osu.Game.Skinning return SkinUtils.As(GetComboColour(Configuration, comboColour.ColourIndex, comboColour.Combo)); case SkinCustomColourLookup customColour: - return SkinUtils.As(getCustomColour(Configuration, customColour.Lookup.ToString())); + return SkinUtils.As(getCustomColour(Configuration, customColour.Lookup.ToString() ?? string.Empty)); case LegacyManiaSkinConfigurationLookup maniaLookup: if (!AllowManiaSkin) @@ -277,7 +277,7 @@ namespace osu.Game.Skinning => source.CustomColours.TryGetValue(lookup, out var col) ? new Bindable(col) : null; private IBindable? getManiaImage(LegacyManiaSkinConfiguration source, string lookup) - => source.ImageLookups.TryGetValue(lookup, out string image) ? new Bindable(image) : null; + => source.ImageLookups.TryGetValue(lookup, out string? image) ? new Bindable(image) : null; private IBindable? legacySettingLookup(SkinConfiguration.LegacySetting legacySetting) where TValue : notnull @@ -298,7 +298,7 @@ namespace osu.Game.Skinning { try { - if (Configuration.ConfigDictionary.TryGetValue(lookup.ToString(), out string val)) + if (Configuration.ConfigDictionary.TryGetValue(lookup.ToString() ?? string.Empty, out string? val)) { // special case for handling skins which use 1 or 0 to signify a boolean state. // ..or in some cases 2 (https://github.com/ppy/osu/issues/18579). diff --git a/osu.Game/Skinning/RealmBackedResourceStore.cs b/osu.Game/Skinning/RealmBackedResourceStore.cs index 0cc90f1dcb..cc887a7a61 100644 --- a/osu.Game/Skinning/RealmBackedResourceStore.cs +++ b/osu.Game/Skinning/RealmBackedResourceStore.cs @@ -52,7 +52,7 @@ namespace osu.Game.Skinning private string? getPathForFile(string filename) { - if (fileToStoragePathMapping.Value.TryGetValue(filename.ToLowerInvariant(), out string path)) + if (fileToStoragePathMapping.Value.TryGetValue(filename.ToLowerInvariant(), out string? path)) return path; return null; diff --git a/osu.Game/Skinning/SkinInfo.cs b/osu.Game/Skinning/SkinInfo.cs index d051149155..7b31c8fe88 100644 --- a/osu.Game/Skinning/SkinInfo.cs +++ b/osu.Game/Skinning/SkinInfo.cs @@ -56,7 +56,7 @@ namespace osu.Game.Skinning return new TrianglesSkin(this, resources); } - return (Skin)Activator.CreateInstance(type, this, resources); + return (Skin)Activator.CreateInstance(type, this, resources)!; } public IList Files { get; } = null!; diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index c5f6f58b86..a9c2bbbd13 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -185,7 +185,7 @@ namespace osu.Game.Tests.Beatmaps private Stream openResource(string name) { - string localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)).AsNonNull(); + string localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().Location).Path)).AsNonNull(); return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}"); } diff --git a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs index c7441f68bd..6a6bde16e8 100644 --- a/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs +++ b/osu.Game/Tests/Beatmaps/DifficultyCalculatorTest.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Beatmaps private Stream openResource(string name) { - string localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path)).AsNonNull(); + string localPath = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().Location).Path)).AsNonNull(); return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}"); } diff --git a/osu.Game/Tests/PollingNotificationsClient.cs b/osu.Game/Tests/PollingNotificationsClient.cs index 571a7a1ed1..450c763170 100644 --- a/osu.Game/Tests/PollingNotificationsClient.cs +++ b/osu.Game/Tests/PollingNotificationsClient.cs @@ -24,8 +24,8 @@ namespace osu.Game.Tests { while (!cancellationToken.IsCancellationRequested) { - await API.PerformAsync(CreateInitialFetchRequest()); - await Task.Delay(1000, cancellationToken); + await API.PerformAsync(CreateInitialFetchRequest()).ConfigureAwait(true); + await Task.Delay(1000, cancellationToken).ConfigureAwait(true); } }, cancellationToken);