1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-21 18:42:56 +08:00

Fix the MOTHERLOAD of undetected issues that are now visible thanks to net6.0

This commit is contained in:
Dean Herbert 2022-12-16 18:16:26 +09:00
parent d6cae991da
commit 27c497145f
67 changed files with 165 additions and 130 deletions

View File

@ -82,7 +82,7 @@ namespace osu.Game.Rulesets.Osu.Replays
private class ReplayFrameComparer : IComparer<ReplayFrame> private class ReplayFrameComparer : IComparer<ReplayFrame>
{ {
public int Compare(ReplayFrame f1, ReplayFrame f2) public int Compare(ReplayFrame? f1, ReplayFrame? f2)
{ {
if (f1 == null) throw new ArgumentNullException(nameof(f1)); if (f1 == null) throw new ArgumentNullException(nameof(f1));
if (f2 == null) throw new ArgumentNullException(nameof(f2)); if (f2 == null) throw new ArgumentNullException(nameof(f2));

View File

@ -245,8 +245,10 @@ namespace osu.Game.Tournament.IPC
{ {
string stableInstallPath; string stableInstallPath;
#pragma warning disable CA1416
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu")) using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", ""); stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(string.Empty)?.ToString()?.Split('"')[1].Replace("osu!.exe", "");
#pragma warning restore CA1416
if (ipcFileExistsInDirectory(stableInstallPath)) if (ipcFileExistsInDirectory(stableInstallPath))
return stableInstallPath; return stableInstallPath;

View File

@ -70,7 +70,7 @@ namespace osu.Game.Tournament
private async Task checkForChanges() 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 // If a save hasn't been triggered by the user yet, populate the initial value
lastSerialisedLadder ??= serialisedLadder; lastSerialisedLadder ??= serialisedLadder;

View File

@ -35,7 +35,7 @@ namespace osu.Game.Audio
public bool Equals(SampleInfo? other) public bool Equals(SampleInfo? other)
=> other != null && sampleNames.SequenceEqual(other.sampleNames); => other != null && sampleNames.SequenceEqual(other.sampleNames);
public override bool Equals(object obj) public override bool Equals(object? obj)
=> obj is SampleInfo other && Equals(other); => obj is SampleInfo other && Equals(other);
} }
} }

View File

@ -44,7 +44,7 @@ namespace osu.Game.Beatmaps
public override async Task<Live<BeatmapSetInfo>?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original) public override async Task<Live<BeatmapSetInfo>?> ImportAsUpdate(ProgressNotification notification, ImportTask importTask, BeatmapSetInfo original)
{ {
var imported = await Import(notification, importTask); var imported = await Import(notification, importTask).ConfigureAwait(false);
if (!imported.Any()) if (!imported.Any())
return null; return null;

View File

@ -178,7 +178,7 @@ namespace osu.Game.Beatmaps
{ {
try try
{ {
await cacheDownloadRequest.PerformAsync(); await cacheDownloadRequest.PerformAsync().ConfigureAwait(false);
} }
catch catch
{ {

View File

@ -16,7 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public void AttachGroup(ControlPointGroup pointGroup) => Time = pointGroup.Time; 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; public virtual Color4 GetRepresentingColour(OsuColour colours) => colours.Yellow;
@ -32,7 +32,7 @@ namespace osu.Game.Beatmaps.ControlPoints
/// </summary> /// </summary>
public ControlPoint DeepClone() public ControlPoint DeepClone()
{ {
var copy = (ControlPoint)Activator.CreateInstance(GetType()); var copy = (ControlPoint)Activator.CreateInstance(GetType())!;
copy.CopyFrom(this); copy.CopyFrom(this);

View File

@ -26,7 +26,7 @@ namespace osu.Game.Beatmaps.ControlPoints
Time = time; 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) public void Add(ControlPoint point)
{ {

View File

@ -51,11 +51,11 @@ namespace osu.Game.Beatmaps
if (!recommendedDifficultyMapping.TryGetValue(r, out double recommendation)) if (!recommendedDifficultyMapping.TryGetValue(r, out double recommendation))
continue; 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; double difference = b.StarRating - recommendation;
return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder return difference >= 0 ? difference * 2 : difference * -1; // prefer easier over harder
}).FirstOrDefault(); });
if (beatmapInfo != null) if (beatmapInfo != null)
return beatmapInfo; return beatmapInfo;
@ -90,7 +90,7 @@ namespace osu.Game.Beatmaps
return recommendedDifficultyMapping return recommendedDifficultyMapping
.OrderByDescending(pair => pair.Value) .OrderByDescending(pair => pair.Value)
.Select(pair => pair.Key) .Select(pair => pair.Key)
.Where(r => !r.Equals(ruleset.Value.ShortName)) .Where(r => !r.Equals(ruleset.Value.ShortName, StringComparison.Ordinal))
.Prepend(ruleset.Value.ShortName); .Prepend(ruleset.Value.ShortName);
} }
} }

View File

@ -91,15 +91,15 @@ namespace osu.Game.Configuration
OrderPosition = orderPosition; OrderPosition = orderPosition;
} }
public int CompareTo(SettingSourceAttribute other) public int CompareTo(SettingSourceAttribute? other)
{ {
if (OrderPosition == other.OrderPosition) if (OrderPosition == other?.OrderPosition)
return 0; return 0;
// unordered items come last (are greater than any ordered items). // unordered items come last (are greater than any ordered items).
if (OrderPosition == null) if (OrderPosition == null)
return 1; return 1;
if (other.OrderPosition == null) if (other?.OrderPosition == null)
return -1; return -1;
// ordered items are sorted by the order value. // ordered items are sorted by the order value.
@ -113,7 +113,7 @@ namespace osu.Game.Configuration
{ {
foreach (var (attr, property) in obj.GetOrderedSettingsSourceProperties()) foreach (var (attr, property) in obj.GetOrderedSettingsSourceProperties())
{ {
object value = property.GetValue(obj); object value = property.GetValue(obj)!;
if (attr.SettingControlType != null) if (attr.SettingControlType != null)
{ {
@ -121,7 +121,7 @@ namespace osu.Game.Configuration
if (controlType.EnumerateBaseTypes().All(t => !t.IsGenericType || t.GetGenericTypeDefinition() != typeof(SettingsItem<>))) if (controlType.EnumerateBaseTypes().All(t => !t.IsGenericType || t.GetGenericTypeDefinition() != typeof(SettingsItem<>)))
throw new InvalidOperationException($"{nameof(SettingSourceAttribute)} had an unsupported custom control type ({controlType.ReadableName()})"); 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<object>.SettingSourceObject))?.SetValue(control, obj); controlType.GetProperty(nameof(SettingsItem<object>.SettingSourceObject))?.SetValue(control, obj);
controlType.GetProperty(nameof(SettingsItem<object>.LabelText))?.SetValue(control, attr.Label); controlType.GetProperty(nameof(SettingsItem<object>.LabelText))?.SetValue(control, attr.Label);
controlType.GetProperty(nameof(SettingsItem<object>.TooltipText))?.SetValue(control, attr.Description); controlType.GetProperty(nameof(SettingsItem<object>.TooltipText))?.SetValue(control, attr.Description);
@ -188,7 +188,7 @@ namespace osu.Game.Configuration
case IBindable bindable: case IBindable bindable:
var dropdownType = typeof(ModSettingsEnumDropdown<>).MakeGenericType(bindable.GetType().GetGenericArguments()[0]); 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<object>.LabelText))?.SetValue(dropdown, attr.Label); dropdownType.GetProperty(nameof(SettingsDropdown<object>.LabelText))?.SetValue(dropdown, attr.Label);
dropdownType.GetProperty(nameof(SettingsDropdown<object>.TooltipText))?.SetValue(dropdown, attr.Description); dropdownType.GetProperty(nameof(SettingsDropdown<object>.TooltipText))?.SetValue(dropdown, attr.Description);
@ -231,7 +231,7 @@ namespace osu.Game.Configuration
// An unknown (e.g. enum) generic type. // An unknown (e.g. enum) generic type.
var valueMethod = u.GetType().GetProperty(nameof(IBindable<int>.Value)); var valueMethod = u.GetType().GetProperty(nameof(IBindable<int>.Value));
Debug.Assert(valueMethod != null); Debug.Assert(valueMethod != null);
return valueMethod.GetValue(u); return valueMethod.GetValue(u)!;
default: default:
// fall back for non-bindable cases. // fall back for non-bindable cases.

View File

@ -66,16 +66,16 @@ namespace osu.Game.Database
switch (content) switch (content)
{ {
case StableContent.Beatmaps: case StableContent.Beatmaps:
return await new LegacyBeatmapImporter(beatmaps).GetAvailableCount(stableStorage); return await new LegacyBeatmapImporter(beatmaps).GetAvailableCount(stableStorage).ConfigureAwait(false);
case StableContent.Skins: case StableContent.Skins:
return await new LegacySkinImporter(skins).GetAvailableCount(stableStorage); return await new LegacySkinImporter(skins).GetAvailableCount(stableStorage).ConfigureAwait(false);
case StableContent.Collections: case StableContent.Collections:
return await new LegacyCollectionImporter(realmAccess).GetAvailableCount(stableStorage); return await new LegacyCollectionImporter(realmAccess).GetAvailableCount(stableStorage).ConfigureAwait(false);
case StableContent.Scores: case StableContent.Scores:
return await new LegacyScoreImporter(scores).GetAvailableCount(stableStorage); return await new LegacyScoreImporter(scores).GetAvailableCount(stableStorage).ConfigureAwait(false);
default: default:
throw new ArgumentException($"Only one {nameof(StableContent)} flag should be specified."); throw new ArgumentException($"Only one {nameof(StableContent)} flag should be specified.");

View File

@ -61,6 +61,6 @@ namespace osu.Game.Database
public override int GetHashCode() => HashCode.Combine(ID); public override int GetHashCode() => HashCode.Combine(ID);
public override string ToString() => PerformRead(i => i.ToString()); public override string? ToString() => PerformRead(i => i.ToString());
} }
} }

View File

@ -71,9 +71,9 @@ namespace osu.Game.Database
bool importSuccessful; bool importSuccessful;
if (originalModel != null) 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 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. // for now a failed import will be marked as a failed download for simplicity.
if (!importSuccessful) if (!importSuccessful)

View File

@ -481,7 +481,7 @@ namespace osu.Game.Database
// server, which we don't use. May want to report upstream or revisit in the future. // server, which we don't use. May want to report upstream or revisit in the future.
using (var realm = getRealmInstance()) using (var realm = getRealmInstance())
// ReSharper disable once AccessToDisposedClosure (WriteAsync should be marked as [InstantHandle]). // ReSharper disable once AccessToDisposedClosure (WriteAsync should be marked as [InstantHandle]).
await realm.WriteAsync(() => action(realm)); await realm.WriteAsync(() => action(realm)).ConfigureAwait(false);
pendingAsyncWrites.Signal(); pendingAsyncWrites.Signal();
}); });
@ -558,7 +558,7 @@ namespace osu.Game.Database
return new InvokeOnDisposal(() => model.PropertyChanged -= onPropertyChanged); return new InvokeOnDisposal(() => model.PropertyChanged -= onPropertyChanged);
void onPropertyChanged(object sender, PropertyChangedEventArgs args) void onPropertyChanged(object? sender, PropertyChangedEventArgs args)
{ {
if (args.PropertyName == propertyName) if (args.PropertyName == propertyName)
onChanged(propLookupCompiled(model)); onChanged(propLookupCompiled(model));

View File

@ -66,10 +66,10 @@ namespace osu.Game.Extensions
foreach (var (_, property) in component.GetSettingsSourceProperties()) 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; continue;
skinnable.CopyAdjustedSetting((IBindable)property.GetValue(component), settingValue); skinnable.CopyAdjustedSetting(((IBindable)property.GetValue(component)!), settingValue);
} }
} }

View File

@ -37,7 +37,7 @@ namespace osu.Game.Extensions
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
tcs.SetCanceled(); tcs.SetCanceled(cancellationToken);
} }
else else
{ {

View File

@ -277,7 +277,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
var samples = sampleMap[feedbackSampleType]; var samples = sampleMap[feedbackSampleType];
if (samples == null || samples.Length == 0) if (samples.Length == 0)
return null; return null;
return samples[RNG.Next(0, samples.Length)]?.GetChannel(); return samples[RNG.Next(0, samples.Length)]?.GetChannel();

View File

@ -27,7 +27,7 @@ namespace osu.Game.Models
public bool IsBot => false; public bool IsBot => false;
public bool Equals(RealmUser other) public bool Equals(RealmUser? other)
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;

View File

@ -39,7 +39,7 @@ namespace osu.Game.Online.API
foreach (var (_, property) in mod.GetSettingsSourceProperties()) foreach (var (_, property) in mod.GetSettingsSourceProperties())
{ {
var bindable = (IBindable)property.GetValue(mod); var bindable = (IBindable)property.GetValue(mod)!;
if (!bindable.IsDefault) if (!bindable.IsDefault)
Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue()); Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue());
@ -60,16 +60,16 @@ namespace osu.Game.Online.API
{ {
foreach (var (_, property) in resultMod.GetSettingsSourceProperties()) 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; continue;
try try
{ {
resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod), settingValue); resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod)!, settingValue);
} }
catch (Exception ex) 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 ShouldSerializeSettings() => Settings.Count > 0;
public bool Equals(APIMod other) public bool Equals(APIMod? other)
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;

View File

@ -143,7 +143,7 @@ namespace osu.Game.Online.API.Requests.Responses
public bool Equals(IRulesetInfo? other) => other is APIRuleset r && this.MatchesOnlineID(r); 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)) if (!(other is APIRuleset ruleset))
throw new ArgumentException($@"Object is not of type {nameof(APIRuleset)}.", nameof(other)); throw new ArgumentException($@"Object is not of type {nameof(APIRuleset)}.", nameof(other));

View File

@ -71,7 +71,7 @@ namespace osu.Game.Online.Chat
{ {
int index = m.Index - captureOffset; int index = m.Index - captureOffset;
string? displayText = string.Format(display, string displayText = string.Format(display,
m.Groups[0], m.Groups[0],
m.Groups["text"].Value, m.Groups["text"].Value,
m.Groups["url"].Value).Trim(); m.Groups["url"].Value).Trim();
@ -109,7 +109,7 @@ namespace osu.Game.Online.Chat
foreach (Match m in regex.Matches(result.Text, startIndex)) foreach (Match m in regex.Matches(result.Text, startIndex))
{ {
int index = m.Index; int index = m.Index;
string? linkText = m.Groups["link"].Value; string linkText = m.Groups["link"].Value;
int indexLength = linkText.Length; int indexLength = linkText.Length;
var details = GetLinkDetails(linkText); var details = GetLinkDetails(linkText);
@ -125,7 +125,7 @@ namespace osu.Game.Online.Chat
public static LinkDetails GetLinkDetails(string url) public static LinkDetails GetLinkDetails(string url)
{ {
string[]? args = url.Split('/', StringSplitOptions.RemoveEmptyEntries); string[] args = url.Split('/', StringSplitOptions.RemoveEmptyEntries);
args[0] = args[0].TrimEnd(':'); args[0] = args[0].TrimEnd(':');
switch (args[0]) 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 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;
} }
} }

View File

@ -5,6 +5,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -61,12 +62,16 @@ namespace osu.Game.Online.Chat
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(e.NewItems != null);
foreach (var channel in e.NewItems.Cast<Channel>()) foreach (var channel in e.NewItems.Cast<Channel>())
channel.NewMessagesArrived += checkNewMessages; channel.NewMessagesArrived += checkNewMessages;
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(e.OldItems != null);
foreach (var channel in e.OldItems.Cast<Channel>()) foreach (var channel in e.OldItems.Cast<Channel>())
channel.NewMessagesArrived -= checkNewMessages; channel.NewMessagesArrived -= checkNewMessages;

View File

@ -68,7 +68,7 @@ namespace osu.Game.Online.Metadata
while (true) while (true)
{ {
Logger.Log($"Requesting catch-up from {lastQueueId.Value}"); 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; lastQueueId.Value = catchUpChanges.LastProcessedQueueID;
@ -78,7 +78,7 @@ namespace osu.Game.Online.Metadata
break; break;
} }
await ProcessChanges(catchUpChanges.BeatmapSetIDs); await ProcessChanges(catchUpChanges.BeatmapSetIDs).ConfigureAwait(true);
} }
} }
catch (Exception e) catch (Exception e)
@ -101,7 +101,7 @@ namespace osu.Game.Online.Metadata
if (!catchingUp) if (!catchingUp)
lastQueueId.Value = updates.LastProcessedQueueID; lastQueueId.Value = updates.LastProcessedQueueID;
await ProcessChanges(updates.BeatmapSetIDs); await ProcessChanges(updates.BeatmapSetIDs).ConfigureAwait(false);
} }
public override Task<BeatmapUpdates> GetChangesSince(int queueId) public override Task<BeatmapUpdates> GetChangesSince(int queueId)

View File

@ -822,7 +822,7 @@ namespace osu.Game.Online.Multiplayer
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
tcs.SetCanceled(); tcs.SetCanceled(cancellationToken);
return; return;
} }

View File

@ -54,10 +54,10 @@ namespace osu.Game.Online.Multiplayer
return UserID == other.UserID; return UserID == other.UserID;
} }
public override bool Equals(object obj) public override bool Equals(object? obj)
{ {
if (ReferenceEquals(this, obj)) return true; if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false; if (obj?.GetType() != GetType()) return false;
return Equals((MultiplayerRoomUser)obj); return Equals((MultiplayerRoomUser)obj);
} }

View File

@ -80,7 +80,7 @@ namespace osu.Game.Online.Multiplayer
try try
{ {
return await connection.InvokeAsync<MultiplayerRoom>(nameof(IMultiplayerServer.JoinRoomWithPassword), roomId, password ?? string.Empty); return await connection.InvokeAsync<MultiplayerRoom>(nameof(IMultiplayerServer.JoinRoomWithPassword), roomId, password ?? string.Empty).ConfigureAwait(false);
} }
catch (HubException exception) catch (HubException exception)
{ {
@ -88,8 +88,8 @@ namespace osu.Game.Online.Multiplayer
{ {
Debug.Assert(connector != null); Debug.Assert(connector != null);
await connector.Reconnect(); await connector.Reconnect().ConfigureAwait(false);
return await JoinRoom(roomId, password); return await JoinRoom(roomId, password).ConfigureAwait(false);
} }
throw; throw;

View File

@ -27,7 +27,7 @@ namespace osu.Game.Online.Notifications
protected sealed override async Task<PersistentEndpointClient> BuildConnectionAsync(CancellationToken cancellationToken) protected sealed override async Task<PersistentEndpointClient> BuildConnectionAsync(CancellationToken cancellationToken)
{ {
var client = await BuildNotificationClientAsync(cancellationToken); var client = await BuildNotificationClientAsync(cancellationToken).ConfigureAwait(false);
client.ChannelJoined = c => ChannelJoined?.Invoke(c); client.ChannelJoined = c => ChannelJoined?.Invoke(c);
client.ChannelParted = c => ChannelParted?.Invoke(c); client.ChannelParted = c => ChannelParted?.Invoke(c);

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Diagnostics; using System.Diagnostics;
using System.Net;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@ -36,11 +37,11 @@ namespace osu.Game.Online.Notifications.WebSocket
public override async Task ConnectAsync(CancellationToken cancellationToken) public override async Task ConnectAsync(CancellationToken cancellationToken)
{ {
await socket.ConnectAsync(new Uri(endpoint), cancellationToken).ConfigureAwait(false); 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); runReadLoop(cancellationToken);
await base.ConnectAsync(cancellationToken); await base.ConnectAsync(cancellationToken).ConfigureAwait(false);
} }
private void runReadLoop(CancellationToken cancellationToken) => Task.Run(async () => private void runReadLoop(CancellationToken cancellationToken) => Task.Run(async () =>
@ -52,7 +53,7 @@ namespace osu.Game.Online.Notifications.WebSocket
{ {
try try
{ {
WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken); WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false);
switch (result.MessageType) switch (result.MessageType)
{ {
@ -72,7 +73,7 @@ namespace osu.Game.Online.Notifications.WebSocket
break; break;
} }
await onMessageReceivedAsync(message); await onMessageReceivedAsync(message).ConfigureAwait(false);
} }
break; break;
@ -81,12 +82,12 @@ namespace osu.Game.Online.Notifications.WebSocket
throw new NotImplementedException("Binary message type not supported."); throw new NotImplementedException("Binary message type not supported.");
case WebSocketMessageType.Close: case WebSocketMessageType.Close:
throw new Exception("Connection closed by remote host."); throw new WebException("Connection closed by remote host.");
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
await InvokeClosed(ex); await InvokeClosed(ex).ConfigureAwait(false);
return; return;
} }
} }
@ -109,7 +110,7 @@ namespace osu.Game.Online.Notifications.WebSocket
if (socket.State != WebSocketState.Open) if (socket.State != WebSocketState.Open)
return; 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) private async Task onMessageReceivedAsync(SocketMessage message)
@ -141,7 +142,7 @@ namespace osu.Game.Online.Notifications.WebSocket
Debug.Assert(messageData != null); Debug.Assert(messageData != null);
foreach (var msg in messageData.Messages) foreach (var msg in messageData.Messages)
HandleChannelJoined(await getChannel(msg.ChannelId)); HandleChannelJoined(await getChannel(msg.ChannelId).ConfigureAwait(false));
HandleMessages(messageData.Messages); HandleMessages(messageData.Messages);
break; break;
@ -150,7 +151,7 @@ namespace osu.Game.Online.Notifications.WebSocket
private async Task<Channel> getChannel(long channelId) private async Task<Channel> getChannel(long channelId)
{ {
if (channelsMap.TryGetValue(channelId, out Channel channel)) if (channelsMap.TryGetValue(channelId, out Channel? channel))
return channel; return channel;
var tsc = new TaskCompletionSource<Channel>(); var tsc = new TaskCompletionSource<Channel>();
@ -166,13 +167,13 @@ namespace osu.Game.Online.Notifications.WebSocket
API.Queue(req); API.Queue(req);
return await tsc.Task; return await tsc.Task.ConfigureAwait(false);
} }
public override async ValueTask DisposeAsync() public override async ValueTask DisposeAsync()
{ {
await base.DisposeAsync(); await base.DisposeAsync().ConfigureAwait(false);
await closeAsync(); await closeAsync().ConfigureAwait(false);
socket.Dispose(); socket.Dispose();
} }
} }

View File

@ -32,7 +32,7 @@ namespace osu.Game.Online.Notifications.WebSocket
req.Failure += ex => tcs.SetException(ex); req.Failure += ex => tcs.SetException(ex);
api.Queue(req); api.Queue(req);
string endpoint = await tcs.Task; string endpoint = await tcs.Task.ConfigureAwait(false);
ClientWebSocket socket = new ClientWebSocket(); ClientWebSocket socket = new ClientWebSocket();
socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}"); socket.Options.SetRequestHeader(@"Authorization", @$"Bearer {api.AccessToken}");

View File

@ -65,11 +65,11 @@ namespace osu.Game.Online
{ {
case APIState.Failing: case APIState.Failing:
case APIState.Offline: case APIState.Offline:
await disconnect(true); await disconnect(true).ConfigureAwait(true);
break; break;
case APIState.Online: case APIState.Online:
await connect(); await connect().ConfigureAwait(true);
break; break;
} }
} }
@ -147,7 +147,7 @@ namespace osu.Game.Online
{ {
bool hasBeenCancelled = cancellationToken.IsCancellationRequested; bool hasBeenCancelled = cancellationToken.IsCancellationRequested;
await disconnect(true); await disconnect(true).ConfigureAwait(false);
if (ex != null) if (ex != null)
await handleErrorAndDelay(ex, CancellationToken.None).ConfigureAwait(false); await handleErrorAndDelay(ex, CancellationToken.None).ConfigureAwait(false);

View File

@ -33,7 +33,8 @@ namespace osu.Game.Online
object? instance = Activator.CreateInstance(resolvedType); object? instance = Activator.CreateInstance(resolvedType);
jsonSerializer.Populate(obj["$value"]!.CreateReader(), instance); if (instance != null)
jsonSerializer.Populate(obj["$value"]!.CreateReader(), instance);
return instance; return instance;
} }

View File

@ -56,7 +56,7 @@ namespace osu.Game.Online.Spectator
try try
{ {
await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), scoreToken, state); await connection.InvokeAsync(nameof(ISpectatorServer.BeginPlaySession), scoreToken, state).ConfigureAwait(false);
} }
catch (Exception exception) catch (Exception exception)
{ {
@ -64,8 +64,8 @@ namespace osu.Game.Online.Spectator
{ {
Debug.Assert(connector != null); Debug.Assert(connector != null);
await connector.Reconnect(); await connector.Reconnect().ConfigureAwait(false);
await BeginPlayingInternal(scoreToken, state); await BeginPlayingInternal(scoreToken, state).ConfigureAwait(false);
} }
// Exceptions can occur if, for instance, the locally played beatmap doesn't have a server-side counterpart. // Exceptions can occur if, for instance, the locally played beatmap doesn't have a server-side counterpart.

View File

@ -184,7 +184,7 @@ namespace osu.Game.Online.Spectator
Header = header; Header = header;
} }
public int CompareTo(TimedFrame other) => Time.CompareTo(other.Time); public int CompareTo(TimedFrame? other) => Time.CompareTo(other?.Time);
} }
} }
} }

View File

@ -352,11 +352,13 @@ namespace osu.Game.Overlays
protected virtual DrawableChannel CreateDrawableChannel(Channel newChannel) => new DrawableChannel(newChannel); 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) switch (args.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
IEnumerable<Channel> newChannels = args.NewItems.OfType<Channel>().Where(isChatChannel); IEnumerable<Channel> newChannels = args.NewItems.OfType<Channel>().Where(isChatChannel);
foreach (var channel in newChannels) foreach (var channel in newChannels)
@ -365,6 +367,8 @@ namespace osu.Game.Overlays
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
IEnumerable<Channel> leftChannels = args.OldItems.OfType<Channel>().Where(isChatChannel); IEnumerable<Channel> leftChannels = args.OldItems.OfType<Channel>().Where(isChatChannel);
foreach (var channel in leftChannels) 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); => channelListing.UpdateAvailableChannels(channelManager.AvailableChannels);
private void handleChatMessage(string message) private void handleChatMessage(string message)

View File

@ -19,6 +19,7 @@ using System;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
@ -359,6 +360,8 @@ namespace osu.Game.Overlays.Comments
switch (args.Action) switch (args.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
onRepliesAdded(args.NewItems.Cast<DrawableComment>()); onRepliesAdded(args.NewItems.Cast<DrawableComment>());
break; break;

View File

@ -301,7 +301,7 @@ namespace osu.Game.Overlays
if (currentStepIndex < steps.Count) 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); loadingShowDelegate = Scheduler.AddDelayed(() => loading.Show(), 200);
nextScreen.OnLoadComplete += _ => nextScreen.OnLoadComplete += _ =>

View File

@ -3,7 +3,6 @@
#nullable disable #nullable disable
using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -131,8 +130,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
{ {
var metadata = beatmapInfo.Metadata; var metadata = beatmapInfo.Metadata;
Debug.Assert(metadata != null);
return new Drawable[] return new Drawable[]
{ {
new OsuSpriteText new OsuSpriteText

View File

@ -4,7 +4,6 @@
#nullable disable #nullable disable
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -269,8 +268,6 @@ namespace osu.Game.Overlays.Profile.Sections.Ranks
{ {
var metadata = beatmapInfo.Metadata; var metadata = beatmapInfo.Metadata;
Debug.Assert(metadata != null);
return new Drawable[] return new Drawable[]
{ {
new OsuSpriteText new OsuSpriteText

View File

@ -3,7 +3,6 @@
#nullable disable #nullable disable
using System.Diagnostics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
@ -29,8 +28,6 @@ namespace osu.Game.Overlays.Settings.Sections.Input
var r = ruleset.CreateInstance(); var r = ruleset.CreateInstance();
Debug.Assert(r != null);
foreach (int variant in r.AvailableVariants) foreach (int variant in r.AvailableVariants)
Add(new VariantBindingsSubsection(ruleset, variant)); Add(new VariantBindingsSubsection(ruleset, variant));
} }

View File

@ -55,6 +55,6 @@ namespace osu.Game.Rulesets.Mods
/// <summary> /// <summary>
/// Create a fresh <see cref="Mod"/> instance based on this mod. /// Create a fresh <see cref="Mod"/> instance based on this mod.
/// </summary> /// </summary>
Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType()); Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType())!;
} }
} }

View File

@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Mods
foreach ((SettingSourceAttribute attr, PropertyInfo property) in this.GetOrderedSettingsSourceProperties()) foreach ((SettingSourceAttribute attr, PropertyInfo property) in this.GetOrderedSettingsSourceProperties())
{ {
var bindable = (IBindable)property.GetValue(this); var bindable = (IBindable)property.GetValue(this)!;
if (!bindable.IsDefault) if (!bindable.IsDefault)
tooltipTexts.Add($"{attr.Label} {bindable}"); tooltipTexts.Add($"{attr.Label} {bindable}");
@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Mods
/// </summary> /// </summary>
public virtual Mod DeepClone() public virtual Mod DeepClone()
{ {
var result = (Mod)Activator.CreateInstance(GetType()); var result = (Mod)Activator.CreateInstance(GetType())!;
result.CopyFrom(this); result.CopyFrom(this);
return result; return result;
} }
@ -150,8 +150,8 @@ namespace osu.Game.Rulesets.Mods
foreach (var (_, prop) in this.GetSettingsSourceProperties()) foreach (var (_, prop) in this.GetSettingsSourceProperties())
{ {
var targetBindable = (IBindable)prop.GetValue(this); var targetBindable = (IBindable)prop.GetValue(this)!;
var sourceBindable = (IBindable)prop.GetValue(source); var sourceBindable = (IBindable)prop.GetValue(source)!;
CopyAdjustedSetting(targetBindable, sourceBindable); 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(null, other)) return false;
if (ReferenceEquals(this, other)) return true; if (ReferenceEquals(this, other)) return true;
@ -209,16 +209,16 @@ namespace osu.Game.Rulesets.Mods
/// <summary> /// <summary>
/// Reset all custom settings for this mod back to their defaults. /// Reset all custom settings for this mod back to their defaults.
/// </summary> /// </summary>
public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType())); public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType())!);
private class ModSettingsEqualityComparer : IEqualityComparer<IBindable> private class ModSettingsEqualityComparer : IEqualityComparer<IBindable>
{ {
public static ModSettingsEqualityComparer Default { get; } = new ModSettingsEqualityComparer(); 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? xValue = x?.GetUnderlyingSettingValue();
object yValue = y.GetUnderlyingSettingValue(); object? yValue = y?.GetUnderlyingSettingValue();
return EqualityComparer<object>.Default.Equals(xValue, yValue); return EqualityComparer<object>.Default.Equals(xValue, yValue);
} }

View File

@ -6,6 +6,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -57,12 +58,16 @@ namespace osu.Game.Rulesets.Objects
switch (args.Action) switch (args.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
foreach (var c in args.NewItems.Cast<PathControlPoint>()) foreach (var c in args.NewItems.Cast<PathControlPoint>())
c.Changed += invalidate; c.Changed += invalidate;
break; break;
case NotifyCollectionChangedAction.Reset: case NotifyCollectionChangedAction.Reset:
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
foreach (var c in args.OldItems.Cast<PathControlPoint>()) foreach (var c in args.OldItems.Cast<PathControlPoint>())
c.Changed -= invalidate; c.Changed -= invalidate;
break; break;

View File

@ -89,6 +89,8 @@ namespace osu.Game.Rulesets
// Confine all mods of each mod type into a single IEnumerable<Mod> // Confine all mods of each mod type into a single IEnumerable<Mod>
.SelectMany(GetModsFor) .SelectMany(GetModsFor)
// Filter out all null mods // 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) .Where(mod => mod != null)
// Resolve MultiMods as their .Mods property // Resolve MultiMods as their .Mods property
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });

View File

@ -53,21 +53,21 @@ namespace osu.Game.Rulesets
public bool Equals(IRulesetInfo? other) => other is RulesetInfo r && Equals(r); 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); return OnlineID.CompareTo(other.OnlineID);
// Official rulesets are always given precedence for the time being. // Official rulesets are always given precedence for the time being.
if (OnlineID >= 0) if (OnlineID >= 0)
return -1; return -1;
if (other.OnlineID >= 0) if (other?.OnlineID >= 0)
return 1; 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)) if (!(other is RulesetInfo ruleset))
throw new ArgumentException($@"Object is not of type {nameof(RulesetInfo)}.", nameof(other)); throw new ArgumentException($@"Object is not of type {nameof(RulesetInfo)}.", nameof(other));

View File

@ -127,7 +127,7 @@ namespace osu.Game.Rulesets
private void loadRulesetFromFile(string file) 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)) if (LoadedAssemblies.Values.Any(t => Path.GetFileNameWithoutExtension(t.Assembly.Location) == filename))
return; return;
@ -158,7 +158,7 @@ namespace osu.Game.Rulesets
} }
catch (Exception e) catch (Exception e)
{ {
LogFailedLoad(assembly.GetName().Name.Split('.').Last(), e); LogFailedLoad(assembly.GetName().Name!.Split('.').Last(), e);
} }
} }

View File

@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Scoring
{ {
foreach (var condition in FailConditions.GetInvocationList()) 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) if (conditionResult)
return true; return true;
} }

View File

@ -317,7 +317,7 @@ namespace osu.Game.Scoring
#endregion #endregion
public bool Equals(ScoreInfo other) => other.ID == ID; public bool Equals(ScoreInfo? other) => other?.ID == ID;
public override string ToString() => this.GetDisplayTitle(); public override string ToString() => this.GetDisplayTitle();
} }

View File

@ -17,7 +17,7 @@ namespace osu.Game.Scoring
protected override ArchiveDownloadRequest<IScoreInfo> CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score); protected override ArchiveDownloadRequest<IScoreInfo> CreateDownloadRequest(IScoreInfo score, bool minimiseDownload) => new DownloadReplayRequest(score);
public override ArchiveDownloadRequest<IScoreInfo> GetExistingDownload(IScoreInfo model) public override ArchiveDownloadRequest<IScoreInfo>? GetExistingDownload(IScoreInfo model)
=> CurrentDownloads.Find(r => r.Model.MatchesOnlineID(model)); => CurrentDownloads.Find(r => r.Model.MatchesOnlineID(model));
} }
} }

View File

@ -5,6 +5,7 @@
using System; using System;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
@ -33,6 +34,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
break; break;
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
foreach (var group in args.NewItems.OfType<ControlPointGroup>()) foreach (var group in args.NewItems.OfType<ControlPointGroup>())
{ {
// as an optimisation, don't add a visualisation if there are already groups with the same types in close proximity. // 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; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
foreach (var group in args.OldItems.OfType<ControlPointGroup>()) foreach (var group in args.OldItems.OfType<ControlPointGroup>())
{ {
var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group)); var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group));

View File

@ -58,6 +58,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
switch (args.Action) switch (args.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
foreach (object o in args.NewItems) foreach (object o in args.NewItems)
{ {
if (blueprintMap.TryGetValue((T)o, out var blueprint)) if (blueprintMap.TryGetValue((T)o, out var blueprint))
@ -67,6 +69,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
foreach (object o in args.OldItems) foreach (object o in args.OldItems)
{ {
if (blueprintMap.TryGetValue((T)o, out var blueprint)) if (blueprintMap.TryGetValue((T)o, out var blueprint))

View File

@ -4,6 +4,7 @@
#nullable disable #nullable disable
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
@ -33,11 +34,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
break; break;
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
foreach (var group in args.NewItems.OfType<ControlPointGroup>()) foreach (var group in args.NewItems.OfType<ControlPointGroup>())
Add(new TimelineControlPointGroup(group)); Add(new TimelineControlPointGroup(group));
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
foreach (var group in args.OldItems.OfType<ControlPointGroup>()) foreach (var group in args.OldItems.OfType<ControlPointGroup>())
{ {
var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group)); var matching = Children.SingleOrDefault(gv => ReferenceEquals(gv.Group, group));

View File

@ -304,7 +304,7 @@ namespace osu.Game.Screens.Edit
/// <param name="index">The index of the <see cref="HitObject"/> to remove.</param> /// <param name="index">The index of the <see cref="HitObject"/> to remove.</param>
public void RemoveAt(int index) public void RemoveAt(int index)
{ {
var hitObject = (HitObject)mutableHitObjects[index]; HitObject hitObject = (HitObject)mutableHitObjects[index]!;
mutableHitObjects.RemoveAt(index); mutableHitObjects.RemoveAt(index);

View File

@ -4,6 +4,7 @@
#nullable disable #nullable disable
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -197,11 +198,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
switch (e.Action) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(e.NewItems != null);
foreach (var added in e.NewItems.OfType<APIUser>()) foreach (var added in e.NewItems.OfType<APIUser>())
addUser(added); addUser(added);
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(e.OldItems != null);
foreach (var removed in e.OldItems.OfType<APIUser>()) foreach (var removed in e.OldItems.OfType<APIUser>())
removeUser(removed); removeUser(removed);
break; break;

View File

@ -6,6 +6,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -117,10 +118,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
switch (args.Action) switch (args.Action)
{ {
case NotifyCollectionChangedAction.Add: case NotifyCollectionChangedAction.Add:
Debug.Assert(args.NewItems != null);
addRooms(args.NewItems.Cast<Room>()); addRooms(args.NewItems.Cast<Room>());
break; break;
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(args.OldItems != null);
removeRooms(args.OldItems.Cast<Room>()); removeRooms(args.OldItems.Cast<Room>());
break; break;
} }

View File

@ -34,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
/// <summary> /// <summary>
/// Whether all spectating players have finished loading. /// Whether all spectating players have finished loading.
/// </summary> /// </summary>
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); protected override UserActivity InitialActivity => new UserActivity.SpectatingMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value);

View File

@ -349,7 +349,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
public void SelectBeatmap() => editPlaylistButton.TriggerClick(); public void SelectBeatmap() => editPlaylistButton.TriggerClick();
private void onPlaylistChanged(object sender, NotifyCollectionChangedEventArgs e) => private void onPlaylistChanged(object? sender, NotifyCollectionChangedEventArgs e) =>
playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}"; playlistLength.Text = $"Length: {Playlist.GetTotalDuration()}";
private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0; private bool hasValidSettings => RoomID.Value == null && NameField.Text.Length > 0 && Playlist.Count > 0;

View File

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using osu.Framework.Allocation; 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) switch (e.Action)
{ {
case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Remove:
Debug.Assert(e.OldItems != null);
foreach (int userId in e.OldItems.OfType<int>()) foreach (int userId in e.OldItems.OfType<int>())
{ {
spectatorClient.StopWatchingUser(userId); spectatorClient.StopWatchingUser(userId);

View File

@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play.HUD
foreach (var (_, property) in component.GetSettingsSourceProperties()) foreach (var (_, property) in component.GetSettingsSourceProperties())
{ {
var bindable = (IBindable)property.GetValue(component); var bindable = (IBindable)property.GetValue(component)!;
if (!bindable.IsDefault) if (!bindable.IsDefault)
Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue()); Settings.Add(property.Name.ToSnakeCase(), bindable.GetUnderlyingSettingValue());
@ -88,7 +88,7 @@ namespace osu.Game.Screens.Play.HUD
{ {
try try
{ {
Drawable d = (Drawable)Activator.CreateInstance(Type); Drawable d = (Drawable)Activator.CreateInstance(Type)!;
d.ApplySkinnableInfo(this); d.ApplySkinnableInfo(this);
return d; return d;
} }

View File

@ -259,10 +259,7 @@ namespace osu.Game.Screens.Utility
var displayMode = host.Window?.CurrentDisplayMode.Value; var displayMode = host.Window?.CurrentDisplayMode.Value;
string exclusive = "unknown"; string exclusive = (host.Renderer as IWindowsRenderer)?.FullscreenCapability.ToString() ?? "unknown";
if (host.Renderer is IWindowsRenderer windowsRenderer)
exclusive = windowsRenderer.FullscreenCapability.ToString();
statusText.Clear(); statusText.Clear();

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -59,9 +58,7 @@ namespace osu.Game.Skinning.Editor
{ {
try try
{ {
var instance = (Drawable)Activator.CreateInstance(type); Drawable instance = (Drawable)Activator.CreateInstance(type)!;
Debug.Assert(instance != null);
if (!((ISkinnableDrawable)instance).IsEditable) return; if (!((ISkinnableDrawable)instance).IsEditable) return;

View File

@ -16,7 +16,7 @@ namespace osu.Game.Skinning
} }
protected virtual string RulesetPrefix => string.Empty; protected virtual string RulesetPrefix => string.Empty;
protected virtual string ComponentName => Component.ToString(); protected virtual string ComponentName => Component.ToString() ?? string.Empty;
public string LookupName => public string LookupName =>
string.Join('/', new[] { "Gameplay", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s))); string.Join('/', new[] { "Gameplay", RulesetPrefix, ComponentName }.Where(s => !string.IsNullOrEmpty(s)));

View File

@ -105,7 +105,7 @@ namespace osu.Game.Skinning
return SkinUtils.As<TValue>(GetComboColour(Configuration, comboColour.ColourIndex, comboColour.Combo)); return SkinUtils.As<TValue>(GetComboColour(Configuration, comboColour.ColourIndex, comboColour.Combo));
case SkinCustomColourLookup customColour: case SkinCustomColourLookup customColour:
return SkinUtils.As<TValue>(getCustomColour(Configuration, customColour.Lookup.ToString())); return SkinUtils.As<TValue>(getCustomColour(Configuration, customColour.Lookup.ToString() ?? string.Empty));
case LegacyManiaSkinConfigurationLookup maniaLookup: case LegacyManiaSkinConfigurationLookup maniaLookup:
if (!AllowManiaSkin) if (!AllowManiaSkin)
@ -277,7 +277,7 @@ namespace osu.Game.Skinning
=> source.CustomColours.TryGetValue(lookup, out var col) ? new Bindable<Color4>(col) : null; => source.CustomColours.TryGetValue(lookup, out var col) ? new Bindable<Color4>(col) : null;
private IBindable<string>? getManiaImage(LegacyManiaSkinConfiguration source, string lookup) private IBindable<string>? getManiaImage(LegacyManiaSkinConfiguration source, string lookup)
=> source.ImageLookups.TryGetValue(lookup, out string image) ? new Bindable<string>(image) : null; => source.ImageLookups.TryGetValue(lookup, out string? image) ? new Bindable<string>(image) : null;
private IBindable<TValue>? legacySettingLookup<TValue>(SkinConfiguration.LegacySetting legacySetting) private IBindable<TValue>? legacySettingLookup<TValue>(SkinConfiguration.LegacySetting legacySetting)
where TValue : notnull where TValue : notnull
@ -298,7 +298,7 @@ namespace osu.Game.Skinning
{ {
try 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. // 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). // ..or in some cases 2 (https://github.com/ppy/osu/issues/18579).

View File

@ -52,7 +52,7 @@ namespace osu.Game.Skinning
private string? getPathForFile(string filename) 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 path;
return null; return null;

View File

@ -56,7 +56,7 @@ namespace osu.Game.Skinning
return new TrianglesSkin(this, resources); return new TrianglesSkin(this, resources);
} }
return (Skin)Activator.CreateInstance(type, this, resources); return (Skin)Activator.CreateInstance(type, this, resources)!;
} }
public IList<RealmNamedFileUsage> Files { get; } = null!; public IList<RealmNamedFileUsage> Files { get; } = null!;

View File

@ -185,7 +185,7 @@ namespace osu.Game.Tests.Beatmaps
private Stream openResource(string name) 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}"); return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
} }

View File

@ -54,7 +54,7 @@ namespace osu.Game.Tests.Beatmaps
private Stream openResource(string name) 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}"); return Assembly.LoadFrom(Path.Combine(localPath, $"{ResourceAssembly}.dll")).GetManifestResourceStream($@"{ResourceAssembly}.Resources.{name}");
} }

View File

@ -24,8 +24,8 @@ namespace osu.Game.Tests
{ {
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{ {
await API.PerformAsync(CreateInitialFetchRequest()); await API.PerformAsync(CreateInitialFetchRequest()).ConfigureAwait(true);
await Task.Delay(1000, cancellationToken); await Task.Delay(1000, cancellationToken).ConfigureAwait(true);
} }
}, cancellationToken); }, cancellationToken);