From 18d4ba5874f3b83fc3e8597992993027bfbfbcb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 18 Mar 2026 16:05:52 +0100 Subject: [PATCH] Tooling updates (#37031) Most of this is as everywhere else, but there's also interesting code inspection fixes from the InspectCode bump, so I'll talk about that a little. ## [Fix suspicious equality in `Hotkey`](https://github.com/ppy/osu/commit/948136e49e88a721827d54e51c5759fe9aca811d) Inspection: https://www.jetbrains.com/help/resharper/TypeWithSuspiciousEqualityIsUsedInRecord.Global.html Pretty annoying to fix, nullable array types are a pain. Does look legit though. ## [Fix `StarDifficulty` using inefficient struct equality](https://github.com/ppy/osu/commit/2db775ebb0bb9f18de67677ef84b993465d26545) Inspection: https://www.jetbrains.com/help/resharper/DefaultStructEqualityIsUsed.Global.html This is a dodgy one because there's no real sane way to define equality on `StarDifficulty` now that it has difficulty and performance attributes jammed into it. So I just basically shut the inspection up with a `record` modifier and move on. Unclear where the equality is used precisely. It's from a global inspection. F12 is very unhelpful when trying to track down usages of `Equals()`. We definitely have `Bindable` instances and those do use equality. Maybe more than that. ## [Use `nameof` expressions to reference enum member names](https://github.com/ppy/osu/commit/aa08175c803bc725f3b15a92174dfe6d1b812d91) Inspection: https://www.jetbrains.com/help/resharper/CanSimplifyDictionaryRemovingWithSingleCall.html Pretty quaint. ## [Prefer using concrete values over `default` or `new()`](https://github.com/ppy/osu/commit/b21ee08d7748be10d42268d5c2eb77369026545d) Inspection: https://www.jetbrains.com/help/resharper/PreferConcreteValueOverDefault.html I could see this one going both ways, but I'm kinda sold on this inspection. Explicit is always better. Saves some allocations in the `CancellationToken` cases as well. ## [Explicitly call `.AsEnumerable()` in some realm usages](https://github.com/ppy/osu/commit/c8ce1ecd42b9d8abb8b9e2ab93d471f463e80401) Inspection: https://www.jetbrains.com/help/resharper/PossibleUnintendedQueryableAsEnumerable.html Not fully sold on this one but it's quick and simple so might as well. ## [Simplify dictionary removal with single `.Remove()` call](https://github.com/ppy/osu/commit/5964ceccea900302df726b7a8ecbf6b74eb2e427) Inspection: https://www.jetbrains.com/help/resharper/CanSimplifyDictionaryRemovingWithSingleCall.html Not much to say. --- .config/dotnet-tools.json | 19 +++++----- .github/workflows/_diffcalc_processor.yml | 2 +- .github/workflows/ci.yml | 35 +++++++++++-------- .github/workflows/deploy.yml | 6 ++-- .github/workflows/report-nunit.yml | 6 ++-- .github/workflows/sentry-release.yml | 4 +-- .../TestSceneHyperDashColouring.cs | 12 +++---- .../Editor/TestSceneSliderReversal.cs | 4 +-- .../Gameplay/TestSceneHitObjectSamples.cs | 2 +- .../TestSceneRevertToDefaultButton.cs | 4 +-- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Beatmaps/BeatmapUpdater.cs | 3 +- osu.Game/Beatmaps/StarDifficulty.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 2 +- osu.Game/Database/RealmAccess.cs | 2 +- osu.Game/Extensions/TaskExtensions.cs | 4 +-- .../Containers/UserTrackingScrollContainer.cs | 2 +- osu.Game/Graphics/OsuIcon.cs | 10 +++--- osu.Game/Graphics/UserInterface/Hotkey.cs | 21 +++++++++++ .../Bindings/DatabasedKeyBindingContainer.cs | 2 +- .../API/Requests/Responses/SoloScoreInfo.cs | 2 +- .../Online/Metadata/OnlineMetadataClient.cs | 2 +- .../WebSocket/DummyNotificationsClient.cs | 2 +- .../WebSocket/INotificationsClient.cs | 2 +- .../WebSocket/WebSocketNotificationsClient.cs | 2 +- .../WebSocketNotificationsClientConnector.cs | 2 +- .../PersistentEndpointClientConnector.cs | 2 +- osu.Game/Overlays/OverlayScrollContainer.cs | 2 +- .../Input/GlobalKeyBindingsSubsection.cs | 2 +- .../Preprocessing/DifficultyHitObject.cs | 4 +-- .../Mods/DifficultyAdjustSettingsControl.cs | 2 +- .../Objects/Pooling/HitObjectEntryManager.cs | 4 +-- osu.Game/Rulesets/UI/DrawableRuleset.cs | 2 +- .../Algorithms/SequentialScrollAlgorithm.cs | 2 +- .../Statistics/PerformanceStatistic.cs | 6 ++-- .../Select/BeatmapLeaderboardScore.Tooltip.cs | 4 +-- 36 files changed, 104 insertions(+), 82 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 17a371079a..dcc47685ee 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,28 +3,25 @@ "isRoot": true, "tools": { "jetbrains.resharper.globaltools": { - "version": "2023.3.3", + "version": "2025.2.3", "commands": [ "jb" - ] - }, - "nvika": { - "version": "4.0.0", - "commands": [ - "nvika" - ] + ], + "rollForward": false }, "codefilesanity": { "version": "0.0.37", "commands": [ "CodeFileSanity" - ] + ], + "rollForward": false }, "ppy.localisationanalyser.tools": { "version": "2025.1208.0", "commands": [ "localisation" - ] + ], + "rollForward": false } } -} +} \ No newline at end of file diff --git a/.github/workflows/_diffcalc_processor.yml b/.github/workflows/_diffcalc_processor.yml index 2f1b2cf893..3ccdee0782 100644 --- a/.github/workflows/_diffcalc_processor.yml +++ b/.github/workflows/_diffcalc_processor.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout diffcalc-sheet-generator - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: path: ${{ inputs.id }} repository: 'smoogipoo/diffcalc-sheet-generator' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7dfe3d11c2..7b98a81c3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ concurrency: permissions: contents: read # to fetch code (actions/checkout) + security-events: write # for reporting InspectCode issues jobs: inspect-code: @@ -13,10 +14,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install .NET 8.0.x - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: "8.0.x" @@ -27,7 +28,7 @@ jobs: run: dotnet restore osu.Desktop.slnf - name: Restore inspectcode cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ github.workspace }}/inspectcode key: inspectcode-${{ hashFiles('.config/dotnet-tools.json', '.github/workflows/ci.yml', 'osu.sln*', 'osu*.slnf', '.editorconfig', '.globalconfig', 'CodeAnalysis/*', '**/*.csproj', '**/*.props') }} @@ -49,10 +50,14 @@ jobs: exit $exit_code - name: InspectCode - run: dotnet jb inspectcode $(pwd)/osu.Desktop.slnf --no-build --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN - - - name: NVika - run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" --treatwarningsaserrors + uses: JetBrains/ReSharper-InspectCode@v0.11 + with: + # this is WTF tier but if you don't specify *both* of these the defaults assume `build: true` + build: false + no-build: true + solution: ./osu.Desktop.slnf + caches-home: inspectcode + verbosity: WARN test: name: Test @@ -71,10 +76,10 @@ jobs: timeout-minutes: 120 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install .NET 8.0.x - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: "8.0.x" @@ -98,7 +103,7 @@ jobs: # Attempt to upload results even if test fails. # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always - name: Upload Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: ${{ always() }} with: name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}} @@ -110,16 +115,16 @@ jobs: timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: microsoft java-version: 11 - name: Install .NET 8.0.x - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: "8.0.x" @@ -135,10 +140,10 @@ jobs: timeout-minutes: 60 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Install .NET 8.0.x - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: "8.0.x" diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 75408d2e8c..5c87d79000 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -44,14 +44,14 @@ jobs: environment: production steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set artifacts directory id: artifactsPath run: echo "::set-output name=nuget_artifacts::${{github.workspace}}/artifacts" - name: Install .NET 8.0.x - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v5 with: dotnet-version: "8.0.x" @@ -77,7 +77,7 @@ jobs: dotnet pack -c Release Templates /p:Version=${{ github.ref_name }} -o ${{steps.artifactsPath.outputs.nuget_artifacts}} - name: Upload artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: osu path: | diff --git a/.github/workflows/report-nunit.yml b/.github/workflows/report-nunit.yml index 14f0208fc8..9bc4d4de20 100644 --- a/.github/workflows/report-nunit.yml +++ b/.github/workflows/report-nunit.yml @@ -22,13 +22,13 @@ jobs: timeout-minutes: 5 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: ${{ github.event.workflow_run.repository.full_name }} ref: ${{ github.event.workflow_run.head_sha }} - name: Download results - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: pattern: osu-test-results-* merge-multiple: true @@ -36,7 +36,7 @@ jobs: github-token: ${{ github.token }} - name: Annotate CI run with test results - uses: dorny/test-reporter@v1.8.0 + uses: dorny/test-reporter@v2.6.0 with: name: Results path: "*.trx" diff --git a/.github/workflows/sentry-release.yml b/.github/workflows/sentry-release.yml index be104d0fd3..5a424e24cd 100644 --- a/.github/workflows/sentry-release.yml +++ b/.github/workflows/sentry-release.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Create Sentry release - uses: getsentry/action-release@v1 + uses: getsentry/action-release@v3 env: SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} SENTRY_ORG: ppy diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs index b343174e6b..fd86fc0899 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDashColouring.cs @@ -193,20 +193,20 @@ namespace osu.Game.Rulesets.Catch.Tests { public Color4 HyperDashColour { - get => Configuration.CustomColours[CatchSkinColour.HyperDash.ToString()]; - set => Configuration.CustomColours[CatchSkinColour.HyperDash.ToString()] = value; + get => Configuration.CustomColours[nameof(CatchSkinColour.HyperDash)]; + set => Configuration.CustomColours[nameof(CatchSkinColour.HyperDash)] = value; } public Color4 HyperDashAfterImageColour { - get => Configuration.CustomColours[CatchSkinColour.HyperDashAfterImage.ToString()]; - set => Configuration.CustomColours[CatchSkinColour.HyperDashAfterImage.ToString()] = value; + get => Configuration.CustomColours[nameof(CatchSkinColour.HyperDashAfterImage)]; + set => Configuration.CustomColours[nameof(CatchSkinColour.HyperDashAfterImage)] = value; } public Color4 HyperDashFruitColour { - get => Configuration.CustomColours[CatchSkinColour.HyperDashFruit.ToString()]; - set => Configuration.CustomColours[CatchSkinColour.HyperDashFruit.ToString()] = value; + get => Configuration.CustomColours[nameof(CatchSkinColour.HyperDashFruit)]; + set => Configuration.CustomColours[nameof(CatchSkinColour.HyperDashFruit)] = value; } public TestSkin() diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs index 058776c527..ffaa422efe 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderReversal.cs @@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor Vector2 oldStartPos = default; Vector2 oldEndPos = default; - double oldDistance = default; + double oldDistance = 0; var oldControlPointTypes = controlPoints.Select(p => p.Type); AddStep("Add slider", () => @@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor Vector2 oldStartPos = default; Vector2 oldEndPos = default; - double oldDistance = default; + double oldDistance = 0; var oldControlPointTypes = segmentedSliderPath.Select(p => p.Type); diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs index 20d63b9bb4..6a822434ac 100644 --- a/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectSamples.cs @@ -258,6 +258,6 @@ namespace osu.Game.Tests.Gameplay } private void disableLayeredHitSounds() - => AddStep("set LayeredHitSounds to false", () => Skin.Configuration.ConfigDictionary[LegacySetting.LayeredHitSounds.ToString()] = "0"); + => AddStep("set LayeredHitSounds to false", () => Skin.Configuration.ConfigDictionary[nameof(LegacySetting.LayeredHitSounds)] = "0"); } } diff --git a/osu.Game.Tests/Visual/Settings/TestSceneRevertToDefaultButton.cs b/osu.Game.Tests/Visual/Settings/TestSceneRevertToDefaultButton.cs index d081f663ba..c29a847f4d 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneRevertToDefaultButton.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneRevertToDefaultButton.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Settings private readonly Bindable current = new Bindable { - Default = default, + Default = 0, Value = 1, }; @@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Settings foreach (var revertToDefaultButton in this.ChildrenOfType>()) revertToDefaultButton.Parent!.Scale = new Vector2(scale); }); - AddToggleStep("toggle default state", state => current.Value = state ? default : 1); + AddToggleStep("toggle default state", state => current.Value = state ? 0 : 1); AddToggleStep("toggle disabled state", state => current.Disabled = state); } } diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 6d1dbaafba..ea3326d294 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -296,7 +296,7 @@ namespace osu.Game.Beatmaps return Realm.Run(r => { r.Refresh(); - return r.All().Where(b => !b.DeletePending).Detach(); + return r.All().Where(b => !b.DeletePending).AsEnumerable().Detach(); }); } diff --git a/osu.Game/Beatmaps/BeatmapUpdater.cs b/osu.Game/Beatmaps/BeatmapUpdater.cs index 72c69393df..559ba64124 100644 --- a/osu.Game/Beatmaps/BeatmapUpdater.cs +++ b/osu.Game/Beatmaps/BeatmapUpdater.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using System.Threading; using System.Threading.Tasks; using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Logging; @@ -36,7 +37,7 @@ namespace osu.Game.Beatmaps public void Queue(Live beatmapSet, MetadataLookupScope lookupScope = MetadataLookupScope.LocalCacheFirst) { Logger.Log($"Queueing change for local beatmap {beatmapSet}"); - Task.Factory.StartNew(() => beatmapSet.PerformRead(b => Process(b, lookupScope)), default, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, + Task.Factory.StartNew(() => beatmapSet.PerformRead(b => Process(b, lookupScope)), CancellationToken.None, TaskCreationOptions.HideScheduler | TaskCreationOptions.RunContinuationsAsynchronously, updateScheduler); } diff --git a/osu.Game/Beatmaps/StarDifficulty.cs b/osu.Game/Beatmaps/StarDifficulty.cs index 9f7a92fe46..696236921d 100644 --- a/osu.Game/Beatmaps/StarDifficulty.cs +++ b/osu.Game/Beatmaps/StarDifficulty.cs @@ -6,7 +6,7 @@ using osu.Game.Rulesets.Difficulty; namespace osu.Game.Beatmaps { - public readonly struct StarDifficulty + public readonly record struct StarDifficulty { /// /// The star difficulty rating for the given beatmap. diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 58af629a63..c9e86f8a4f 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -265,7 +265,7 @@ namespace osu.Game.Beatmaps using (var cancellationTokenSource = new CancellationTokenSource(10_000)) { // don't apply the default timeout when debugger is attached (may be breakpointing / debugging). - return GetPlayableBeatmap(ruleset, mods ?? Array.Empty(), Debugger.IsAttached ? new CancellationToken() : cancellationTokenSource.Token); + return GetPlayableBeatmap(ruleset, mods ?? Array.Empty(), Debugger.IsAttached ? CancellationToken.None : cancellationTokenSource.Token); } } catch (OperationCanceledException) diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index fa54ed538a..379366b7e0 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -1227,7 +1227,7 @@ namespace osu.Game.Database var oldKeyBindingsQuery = migration.NewRealm .All() .Where(kb => kb.RulesetName == @"mania" && kb.Variant == variant); - var oldKeyBindings = oldKeyBindingsQuery.Detach(); + var oldKeyBindings = oldKeyBindingsQuery.AsEnumerable().Detach(); migration.NewRealm.RemoveRange(oldKeyBindingsQuery); diff --git a/osu.Game/Extensions/TaskExtensions.cs b/osu.Game/Extensions/TaskExtensions.cs index 43abb59042..4cdb895d48 100644 --- a/osu.Game/Extensions/TaskExtensions.cs +++ b/osu.Game/Extensions/TaskExtensions.cs @@ -55,9 +55,9 @@ namespace osu.Game.Extensions { tcs.TrySetResult(true); } - }, cancellationToken: default); + }, cancellationToken: CancellationToken.None); } - }, cancellationToken: default); + }, cancellationToken: CancellationToken.None); // importantly, we are not returning the continuation itself but rather a task which represents its status in sequential execution order. // this will not be cancelled or completed until the previous task has also. diff --git a/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs b/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs index ab17c3f9e3..52a6b12166 100644 --- a/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs +++ b/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs @@ -35,7 +35,7 @@ namespace osu.Game.Graphics.Containers { } - protected override void OnUserScroll(double value, bool animated = true, double? distanceDecay = default) + protected override void OnUserScroll(double value, bool animated = true, double? distanceDecay = null) { UserScrolling = true; base.OnUserScroll(value, animated, distanceDecay); diff --git a/osu.Game/Graphics/OsuIcon.cs b/osu.Game/Graphics/OsuIcon.cs index 5eccbabf95..f8fc263f4e 100644 --- a/osu.Game/Graphics/OsuIcon.cs +++ b/osu.Game/Graphics/OsuIcon.cs @@ -688,11 +688,11 @@ namespace osu.Game.Graphics public class Glyph : ITexturedCharacterGlyph { - public float XOffset => default; - public float YOffset => default; - public float XAdvance => default; - public float Baseline => default; - public char Character => default; + public float XOffset => 0; + public float YOffset => 0; + public float XAdvance => 0; + public float Baseline => 0; + public char Character => '\0'; public float GetKerning(T lastGlyph) where T : ICharacterGlyph => throw new NotImplementedException(); diff --git a/osu.Game/Graphics/UserInterface/Hotkey.cs b/osu.Game/Graphics/UserInterface/Hotkey.cs index 8b3014bdc5..3e2b87914e 100644 --- a/osu.Game/Graphics/UserInterface/Hotkey.cs +++ b/osu.Game/Graphics/UserInterface/Hotkey.cs @@ -1,6 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using osu.Framework.Input; @@ -55,5 +57,24 @@ namespace osu.Game.Graphics.UserInterface return result; } + + public bool Equals(Hotkey other) + { + if (KeyCombinations == null && other.KeyCombinations != null) + return false; + + if (KeyCombinations != null && other.KeyCombinations == null) + return false; + + bool result = (KeyCombinations == null && other.KeyCombinations == null) || KeyCombinations!.SequenceEqual(other.KeyCombinations!); + result &= GlobalAction == other.GlobalAction; + result &= PlatformAction == other.PlatformAction; + return result; + } + + public override int GetHashCode() + { + return HashCode.Combine(StructuralComparisons.StructuralEqualityComparer.GetHashCode(KeyCombinations ?? []), GlobalAction, PlatformAction); + } } } diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs index be025e3aa2..cbb0e81e06 100644 --- a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs +++ b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs @@ -74,7 +74,7 @@ namespace osu.Game.Input.Bindings { var defaults = DefaultKeyBindings.ToList(); - List newBindings = realmKeyBindings.Detach() + List newBindings = realmKeyBindings.AsEnumerable().Detach() // this ordering is important to ensure that we read entries from the database in the order // enforced by DefaultKeyBindings. allow for song select to handle actions that may otherwise // have been eaten by the music controller due to query order. diff --git a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs index 58c819f391..2c5db66658 100644 --- a/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/SoloScoreInfo.cs @@ -145,7 +145,7 @@ namespace osu.Game.Online.API.Requests.Responses // Generally this is required because this model may be used by server-side components, but // we don't want to bother sending these fields in score submission requests, for instance. public bool ShouldSerializeEndedAt() => EndedAt != default; - public bool ShouldSerializeStartedAt() => StartedAt != default; + public bool ShouldSerializeStartedAt() => StartedAt != null; public bool ShouldSerializeLegacyScoreId() => LegacyScoreId != null; public bool ShouldSerializeLegacyTotalScore() => LegacyTotalScore != null; public bool ShouldSerializeMods() => Mods.Length > 0; diff --git a/osu.Game/Online/Metadata/OnlineMetadataClient.cs b/osu.Game/Online/Metadata/OnlineMetadataClient.cs index 0853ccf9df..a30268d7bb 100644 --- a/osu.Game/Online/Metadata/OnlineMetadataClient.cs +++ b/osu.Game/Online/Metadata/OnlineMetadataClient.cs @@ -175,7 +175,7 @@ namespace osu.Game.Online.Metadata public override Task GetChangesSince(int queueId) { if (connector?.IsConnected.Value != true) - return Task.FromCanceled(default); + return Task.FromCanceled(CancellationToken.None); Logger.Log($"Requesting any changes since last known queue id {queueId}"); diff --git a/osu.Game/Online/Notifications/WebSocket/DummyNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/DummyNotificationsClient.cs index c1f3d25be7..282e2c3af7 100644 --- a/osu.Game/Online/Notifications/WebSocket/DummyNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/DummyNotificationsClient.cs @@ -16,7 +16,7 @@ namespace osu.Game.Online.Notifications.WebSocket public Func? HandleMessage; - public Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = default) + public Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = null) { if (HandleMessage?.Invoke(message) != true) throw new InvalidOperationException($@"{nameof(DummyNotificationsClient)} cannot process this message."); diff --git a/osu.Game/Online/Notifications/WebSocket/INotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/INotificationsClient.cs index 9a222d0fdd..44b8036e28 100644 --- a/osu.Game/Online/Notifications/WebSocket/INotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/INotificationsClient.cs @@ -26,6 +26,6 @@ namespace osu.Game.Online.Notifications.WebSocket /// /// Sends a to the notification server. /// - Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = default); + Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = null); } } diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs index 854f46880f..03427ab8fc 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClient.cs @@ -97,7 +97,7 @@ namespace osu.Game.Online.Notifications.WebSocket } } - public async Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = default) + public async Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = null) { if (socket.State != WebSocketState.Open) return; diff --git a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs index 596322d377..35529c8232 100644 --- a/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs +++ b/osu.Game/Online/Notifications/WebSocket/WebSocketNotificationsClientConnector.cs @@ -46,7 +46,7 @@ namespace osu.Game.Online.Notifications.WebSocket return client; } - public Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = default) + public Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = null) { if (CurrentConnection is not WebSocketNotificationsClient webSocketClient) return Task.CompletedTask; diff --git a/osu.Game/Online/PersistentEndpointClientConnector.cs b/osu.Game/Online/PersistentEndpointClientConnector.cs index 2674c29103..7064906be4 100644 --- a/osu.Game/Online/PersistentEndpointClientConnector.cs +++ b/osu.Game/Online/PersistentEndpointClientConnector.cs @@ -173,7 +173,7 @@ namespace osu.Game.Online // make sure a disconnect wasn't triggered (and this is still the active connection). if (!hasBeenCancelled) - await Task.Run(connect, default).ConfigureAwait(false); + await Task.Run(connect, CancellationToken.None).ConfigureAwait(false); } protected Task Disconnect() => disconnect(true); diff --git a/osu.Game/Overlays/OverlayScrollContainer.cs b/osu.Game/Overlays/OverlayScrollContainer.cs index a197748687..ee07937639 100644 --- a/osu.Game/Overlays/OverlayScrollContainer.cs +++ b/osu.Game/Overlays/OverlayScrollContainer.cs @@ -71,7 +71,7 @@ namespace osu.Game.Overlays Button.State = Target > button_scroll_position || lastScrollTarget.Value != null ? Visibility.Visible : Visibility.Hidden; } - protected override void OnUserScroll(double value, bool animated = true, double? distanceDecay = default) + protected override void OnUserScroll(double value, bool animated = true, double? distanceDecay = null) { base.OnUserScroll(value, animated, distanceDecay); diff --git a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSubsection.cs index 2e42e46330..7048b62c29 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSubsection.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { var bindings = realm.All() .Where(b => b.RulesetName == null && b.Variant == null) - .Detach(); + .AsEnumerable().Detach(); var actionsInSection = GlobalActionContainer.GetGlobalActionsFor(category).Cast().ToHashSet(); return bindings.Where(kb => actionsInSection.Contains(kb.ActionInt)); diff --git a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs index 9785865192..117ea431a0 100644 --- a/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs +++ b/osu.Game/Rulesets/Difficulty/Preprocessing/DifficultyHitObject.cs @@ -67,13 +67,13 @@ namespace osu.Game.Rulesets.Difficulty.Preprocessing public DifficultyHitObject Previous(int backwardsIndex) { int index = Index - (backwardsIndex + 1); - return index >= 0 && index < difficultyHitObjects.Count ? difficultyHitObjects[index] : default; + return index >= 0 && index < difficultyHitObjects.Count ? difficultyHitObjects[index] : null; } public DifficultyHitObject Next(int forwardsIndex) { int index = Index + (forwardsIndex + 1); - return index >= 0 && index < difficultyHitObjects.Count ? difficultyHitObjects[index] : default; + return index >= 0 && index < difficultyHitObjects.Count ? difficultyHitObjects[index] : null; } } } diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 6697a8d848..af39fdcc07 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Mods } } - public DifficultyBindableWithCurrent(float? defaultValue = default) + public DifficultyBindableWithCurrent(float? defaultValue = null) : base(defaultValue) { } diff --git a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs index 7977166cb2..479a731607 100644 --- a/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs +++ b/osu.Game/Rulesets/Objects/Pooling/HitObjectEntryManager.cs @@ -69,11 +69,9 @@ namespace osu.Game.Rulesets.Objects.Pooling HitObject hitObject = entry.HitObject; - if (!entryMap.ContainsKey(hitObject)) + if (!entryMap.Remove(hitObject)) throw new InvalidOperationException($@"The {nameof(HitObjectLifetimeEntry)} is not contained in this {nameof(HitObjectEntryManager)}."); - entryMap.Remove(hitObject); - // If the entry has a parent, unset it and remove the entry from the parents' children. if (parentMap.Remove(entry, out var parent) && entryMap.TryGetValue(parent, out var parentEntry)) parentEntry.NestedEntries.Remove(entry); diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index 31ff81456c..0fd90f5459 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -198,7 +198,7 @@ namespace osu.Game.Rulesets.UI applyRulesetMods(Mods, config); - loadObjects(cancellationToken ?? default); + loadObjects(cancellationToken ?? CancellationToken.None); } /// diff --git a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs index 774beb20c7..cc20d68ad9 100644 --- a/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs +++ b/osu.Game/Rulesets/UI/Scrolling/Algorithms/SequentialScrollAlgorithm.cs @@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms /// public readonly double Position; - public PositionMapping(double time, MultiplierControlPoint controlPoint = null, double position = default) + public PositionMapping(double time, MultiplierControlPoint controlPoint = null, double position = 0) { Time = time; ControlPoint = controlPoint; diff --git a/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs b/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs index 8a84501a17..1c0ad8c88e 100644 --- a/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs +++ b/osu.Game/Screens/Ranking/Expanded/Statistics/PerformanceStatistic.cs @@ -49,17 +49,17 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics { Task.Run(async () => { - var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo!, score.Ruleset, score.Mods, cancellationToken ?? default).ConfigureAwait(false); + var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo!, score.Ruleset, score.Mods, cancellationToken ?? CancellationToken.None).ConfigureAwait(false); var performanceCalculator = score.Ruleset.CreateInstance().CreatePerformanceCalculator(); // Performance calculation requires the beatmap and ruleset to be locally available. If not, return a default value. if (attributes?.DifficultyAttributes == null || performanceCalculator == null) return; - var result = await performanceCalculator.CalculateAsync(score, attributes.Value.DifficultyAttributes, cancellationToken ?? default).ConfigureAwait(false); + var result = await performanceCalculator.CalculateAsync(score, attributes.Value.DifficultyAttributes, cancellationToken ?? CancellationToken.None).ConfigureAwait(false); Schedule(() => setPerformanceValue(score, result.Total)); - }, cancellationToken ?? default); + }, cancellationToken ?? CancellationToken.None); } } diff --git a/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs b/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs index bd3b6f16b3..64a5f4334e 100644 --- a/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs +++ b/osu.Game/Screens/Select/BeatmapLeaderboardScore.Tooltip.cs @@ -291,7 +291,7 @@ namespace osu.Game.Screens.Select Task.Run(async () => { - var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo!, score.Ruleset, score.Mods, cancellationToken ?? default).ConfigureAwait(false); + var attributes = await difficultyCache.GetDifficultyAsync(score.BeatmapInfo!, score.Ruleset, score.Mods, cancellationToken ?? CancellationToken.None).ConfigureAwait(false); var performanceCalculator = score.Ruleset.CreateInstance().CreatePerformanceCalculator(); // Performance calculation requires the beatmap and ruleset to be locally available. If not, return a default value. @@ -301,7 +301,7 @@ namespace osu.Game.Screens.Select var result = await performanceCalculator.CalculateAsync(score, attributes.Value.DifficultyAttributes, cancellationToken ?? CancellationToken.None).ConfigureAwait(false); Schedule(() => setPerformanceValue(score, result.Total)); - }, cancellationToken ?? default); + }, cancellationToken ?? CancellationToken.None); } private void setPerformanceValue(ScoreInfo scoreInfo, double pp)