1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-13 19:54:15 +08:00

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<StarDifficulty>` 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.
This commit is contained in:
Bartłomiej Dach
2026-03-18 16:05:52 +01:00
committed by GitHub
Unverified
parent a85c128cdf
commit 18d4ba5874
36 changed files with 104 additions and 82 deletions
+8 -11
View File
@@ -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
}
}
}
}
+1 -1
View File
@@ -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'
+20 -15
View File
@@ -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"
+3 -3
View File
@@ -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: |
+3 -3
View File
@@ -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"
+2 -2
View File
@@ -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
@@ -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()
@@ -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);
@@ -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");
}
}
@@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Settings
private readonly Bindable<float> current = new Bindable<float>
{
Default = default,
Default = 0,
Value = 1,
};
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Visual.Settings
foreach (var revertToDefaultButton in this.ChildrenOfType<RevertToDefaultButton<float>>())
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);
}
}
+1 -1
View File
@@ -296,7 +296,7 @@ namespace osu.Game.Beatmaps
return Realm.Run(r =>
{
r.Refresh();
return r.All<BeatmapSetInfo>().Where(b => !b.DeletePending).Detach();
return r.All<BeatmapSetInfo>().Where(b => !b.DeletePending).AsEnumerable().Detach();
});
}
+2 -1
View File
@@ -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<BeatmapSetInfo> 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);
}
+1 -1
View File
@@ -6,7 +6,7 @@ using osu.Game.Rulesets.Difficulty;
namespace osu.Game.Beatmaps
{
public readonly struct StarDifficulty
public readonly record struct StarDifficulty
{
/// <summary>
/// The star difficulty rating for the given beatmap.
+1 -1
View File
@@ -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<Mod>(), Debugger.IsAttached ? new CancellationToken() : cancellationTokenSource.Token);
return GetPlayableBeatmap(ruleset, mods ?? Array.Empty<Mod>(), Debugger.IsAttached ? CancellationToken.None : cancellationTokenSource.Token);
}
}
catch (OperationCanceledException)
+1 -1
View File
@@ -1227,7 +1227,7 @@ namespace osu.Game.Database
var oldKeyBindingsQuery = migration.NewRealm
.All<RealmKeyBinding>()
.Where(kb => kb.RulesetName == @"mania" && kb.Variant == variant);
var oldKeyBindings = oldKeyBindingsQuery.Detach();
var oldKeyBindings = oldKeyBindingsQuery.AsEnumerable().Detach();
migration.NewRealm.RemoveRange(oldKeyBindingsQuery);
+2 -2
View File
@@ -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.
@@ -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);
+5 -5
View File
@@ -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>(T lastGlyph) where T : ICharacterGlyph => throw new NotImplementedException();
+21
View File
@@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
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);
}
}
}
@@ -74,7 +74,7 @@ namespace osu.Game.Input.Bindings
{
var defaults = DefaultKeyBindings.ToList();
List<RealmKeyBinding> newBindings = realmKeyBindings.Detach()
List<RealmKeyBinding> 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.
@@ -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;
@@ -175,7 +175,7 @@ namespace osu.Game.Online.Metadata
public override Task<BeatmapUpdates> GetChangesSince(int queueId)
{
if (connector?.IsConnected.Value != true)
return Task.FromCanceled<BeatmapUpdates>(default);
return Task.FromCanceled<BeatmapUpdates>(CancellationToken.None);
Logger.Log($"Requesting any changes since last known queue id {queueId}");
@@ -16,7 +16,7 @@ namespace osu.Game.Online.Notifications.WebSocket
public Func<SocketMessage, bool>? 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.");
@@ -26,6 +26,6 @@ namespace osu.Game.Online.Notifications.WebSocket
/// <summary>
/// Sends a <see cref="SocketMessage"/> to the notification server.
/// </summary>
Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = default);
Task SendAsync(SocketMessage message, CancellationToken? cancellationToken = null);
}
}
@@ -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;
@@ -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;
@@ -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);
+1 -1
View File
@@ -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);
@@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
var bindings = realm.All<RealmKeyBinding>()
.Where(b => b.RulesetName == null && b.Variant == null)
.Detach();
.AsEnumerable().Detach();
var actionsInSection = GlobalActionContainer.GetGlobalActionsFor(category).Cast<int>().ToHashSet();
return bindings.Where(kb => actionsInSection.Contains(kb.ActionInt));
@@ -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;
}
}
}
@@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Mods
}
}
public DifficultyBindableWithCurrent(float? defaultValue = default)
public DifficultyBindableWithCurrent(float? defaultValue = null)
: base(defaultValue)
{
}
@@ -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);
+1 -1
View File
@@ -198,7 +198,7 @@ namespace osu.Game.Rulesets.UI
applyRulesetMods(Mods, config);
loadObjects(cancellationToken ?? default);
loadObjects(cancellationToken ?? CancellationToken.None);
}
/// <summary>
@@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.UI.Scrolling.Algorithms
/// </summary>
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;
@@ -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);
}
}
@@ -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)