mirror of
https://github.com/ppy/osu-tools.git
synced 2025-06-07 23:07:01 +09:00
Merge branch 'master' into buyaspacecube/combined-profile-4-merge
This commit is contained in:
commit
534b01c409
49 changed files with 561 additions and 271 deletions
|
@ -1,6 +1,17 @@
|
|||
# EditorConfig is awesome: http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*.{csproj,props,targets}]
|
||||
charset = utf-8-bom
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[g_*.cs]
|
||||
generated_code = true
|
||||
|
||||
[*.cs]
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
|
@ -8,6 +19,9 @@ indent_style = space
|
|||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
#license header
|
||||
file_header_template = Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.\nSee the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#Roslyn naming styles
|
||||
|
||||
#PascalCase for public and protected members
|
||||
|
@ -121,7 +135,7 @@ dotnet_style_qualification_for_event = false:warning
|
|||
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
|
||||
dotnet_style_predefined_type_for_member_access = true:warning
|
||||
csharp_style_var_when_type_is_apparent = true:none
|
||||
csharp_style_var_for_built_in_types = true:none
|
||||
csharp_style_var_for_built_in_types = false:warning
|
||||
csharp_style_var_elsewhere = true:silent
|
||||
|
||||
#Style - modifiers
|
||||
|
@ -165,7 +179,7 @@ csharp_style_unused_value_assignment_preference = discard_variable:warning
|
|||
|
||||
#Style - variable declaration
|
||||
csharp_style_inlined_variable_declaration = true:warning
|
||||
csharp_style_deconstructed_variable_declaration = true:warning
|
||||
csharp_style_deconstructed_variable_declaration = false:silent
|
||||
|
||||
#Style - other C# 7.x features
|
||||
dotnet_style_prefer_inferred_tuple_names = true:warning
|
||||
|
@ -176,19 +190,20 @@ dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
|
|||
#Style - C# 8 features
|
||||
csharp_prefer_static_local_function = true:warning
|
||||
csharp_prefer_simple_using_statement = true:silent
|
||||
csharp_style_prefer_index_operator = true:warning
|
||||
csharp_style_prefer_range_operator = true:warning
|
||||
csharp_style_prefer_index_operator = false:silent
|
||||
csharp_style_prefer_range_operator = false:silent
|
||||
csharp_style_prefer_switch_expression = false:none
|
||||
|
||||
#Supressing roslyn built-in analyzers
|
||||
# Suppress: EC112
|
||||
csharp_style_namespace_declarations = block_scoped:warning
|
||||
|
||||
#Private method is unused
|
||||
dotnet_diagnostic.IDE0051.severity = silent
|
||||
#Private member is unused
|
||||
dotnet_diagnostic.IDE0052.severity = silent
|
||||
#Style - C# 12 features
|
||||
csharp_style_prefer_primary_constructors = false
|
||||
|
||||
#Rules for disposable
|
||||
dotnet_diagnostic.IDE0067.severity = none
|
||||
dotnet_diagnostic.IDE0068.severity = none
|
||||
dotnet_diagnostic.IDE0069.severity = none
|
||||
[*.{yaml,yml}]
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
dotnet_diagnostic.OLOC001.words_in_name = 5
|
||||
dotnet_diagnostic.OLOC001.license_header = // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.\n// See the LICENCE file in the repository root for full licence text.
|
||||
|
|
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -15,6 +15,7 @@ App.config text eol=crlf
|
|||
*.cmd text eol=crlf
|
||||
*.snippet text eol=crlf
|
||||
*.manifest text eol=crlf
|
||||
*.licenseheader text eol=crlf
|
||||
|
||||
# Check out with lf (UNIX) line endings
|
||||
*.sh text eol=lf
|
||||
|
|
113
.gitignore
vendored
113
.gitignore
vendored
|
@ -10,12 +10,8 @@
|
|||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
### Cake ###
|
||||
tools/**
|
||||
build/tools/**
|
||||
|
||||
# Build results
|
||||
bin/[Dd]ebug/
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
|
@ -102,7 +98,6 @@ $tf/
|
|||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
inspectcode
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
@ -196,6 +191,7 @@ ClientBin/
|
|||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
Resource.designer.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
|
@ -251,21 +247,102 @@ paket-files/
|
|||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/.idea.osu.Tools/.idea/*.xml
|
||||
.idea/.idea.osu.Tools/.idea/codeStyles/*.xml
|
||||
.idea/.idea.osu.Tools/.idea/dataSources/*.xml
|
||||
.idea/.idea.osu.Tools/.idea/dictionaries/*.xml
|
||||
.idea/.idea.osu.Tools/*.iml
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
Staging/
|
||||
|
||||
# Cake #
|
||||
/tools/**
|
||||
/build/tools/**
|
||||
/build/temp/**
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
.idea/*/.idea/projectSettingsUpdater.xml
|
||||
.idea/*/.idea/encodings.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
.idea/modules.xml
|
||||
.idea/*.iml
|
||||
.idea/modules
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
|
||||
# inspectcode
|
||||
inspectcodereport.xml
|
||||
inspectcode
|
||||
|
||||
# BenchmarkDotNet
|
||||
/BenchmarkDotNet.Artifacts
|
||||
|
||||
*.GeneratedMSBuildEditorConfig.editorconfig
|
||||
|
||||
# Fody (pulled in by Realm) - schema file
|
||||
FodyWeavers.xsd
|
||||
|
||||
.idea/.idea.osu.Desktop/.idea/misc.xml
|
||||
.idea/.idea.osu.Android/.idea/deploymentTargetDropDown.xml
|
||||
|
||||
PerformanceCalculator/cache/
|
||||
|
|
20
CodeAnalysis/BannedSymbols.txt
Normal file
20
CodeAnalysis/BannedSymbols.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
|
||||
M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
|
||||
M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead.
|
||||
M:System.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead.
|
||||
T:System.IComparable;Don't use non-generic IComparable. Use generic version instead.
|
||||
T:SixLabors.ImageSharp.IDeepCloneable`1;Use osu.Game.Utils.IDeepCloneable<T> instead.
|
||||
M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.
|
||||
M:osu.Framework.Bindables.IBindableList`1.GetBoundCopy();Fails on iOS. Use manual ctor + BindTo instead. (see https://github.com/mono/mono/issues/19900)
|
||||
T:NuGet.Packaging.CollectionExtensions;Don't use internal extension methods.
|
||||
M:Realms.IRealmCollection`1.SubscribeForNotifications`1(Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IRealmCollection<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:System.Guid.#ctor;Probably meaning to use Guid.NewGuid() instead. If actually wanting empty, use Guid.Empty.
|
||||
M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IQueryable<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IList<T>,NotificationCallbackDelegate<T>) instead.
|
||||
M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks.
|
||||
P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks.
|
||||
M:System.Threading.ManualResetEventSlim.Wait();Specify a timeout to avoid waiting forever.
|
||||
M:Humanizer.InflectorExtensions.Pascalize(System.String);Humanizer's .Pascalize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToPascalCase() instead.
|
||||
M:Humanizer.InflectorExtensions.Camelize(System.String);Humanizer's .Camelize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToCamelCase() instead.
|
||||
M:Humanizer.InflectorExtensions.Underscore(System.String);Humanizer's .Underscore() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToSnakeCase() instead.
|
||||
M:Humanizer.InflectorExtensions.Kebaberize(System.String);Humanizer's .Kebaberize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToKebabCase() instead.
|
109
CodeAnalysis/osu.Tools.globalconfig
Normal file
109
CodeAnalysis/osu.Tools.globalconfig
Normal file
|
@ -0,0 +1,109 @@
|
|||
# .NET Code Style
|
||||
# IDE styles reference: https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/
|
||||
is_global = true
|
||||
|
||||
# IDE0001: Simplify names
|
||||
dotnet_diagnostic.IDE0001.severity = warning
|
||||
|
||||
# IDE0002: Simplify member access
|
||||
dotnet_diagnostic.IDE0002.severity = warning
|
||||
|
||||
# IDE0003: Remove qualification
|
||||
dotnet_diagnostic.IDE0003.severity = warning
|
||||
|
||||
# IDE0004: Remove unnecessary cast
|
||||
dotnet_diagnostic.IDE0004.severity = warning
|
||||
|
||||
# IDE0005: Remove unnecessary imports
|
||||
dotnet_diagnostic.IDE0005.severity = warning
|
||||
|
||||
# IDE0034: Simplify default literal
|
||||
dotnet_diagnostic.IDE0034.severity = warning
|
||||
|
||||
# IDE0036: Sort modifiers
|
||||
dotnet_diagnostic.IDE0036.severity = warning
|
||||
|
||||
# IDE0040: Add accessibility modifier
|
||||
dotnet_diagnostic.IDE0040.severity = warning
|
||||
|
||||
# IDE0049: Use keyword for type name
|
||||
dotnet_diagnostic.IDE0040.severity = warning
|
||||
|
||||
# IDE0055: Fix formatting
|
||||
dotnet_diagnostic.IDE0055.severity = warning
|
||||
|
||||
# IDE0051: Private method is unused
|
||||
dotnet_diagnostic.IDE0051.severity = silent
|
||||
|
||||
# IDE0052: Private member is unused
|
||||
dotnet_diagnostic.IDE0052.severity = silent
|
||||
|
||||
# IDE0073: File header
|
||||
dotnet_diagnostic.IDE0073.severity = warning
|
||||
|
||||
# IDE0130: Namespace mismatch with folder
|
||||
dotnet_diagnostic.IDE0130.severity = warning
|
||||
|
||||
# IDE1006: Naming style
|
||||
dotnet_diagnostic.IDE1006.severity = warning
|
||||
|
||||
# CA1305: Specify IFormatProvider
|
||||
# Too many noisy warnings for parsing/formatting numbers
|
||||
dotnet_diagnostic.CA1305.severity = none
|
||||
|
||||
# CA1507: Use nameof to express symbol names
|
||||
# Flaggs serialization name attributes
|
||||
dotnet_diagnostic.CA1507.severity = suggestion
|
||||
|
||||
# CA1806: Do not ignore method results
|
||||
# The usages for numeric parsing are explicitly optional
|
||||
dotnet_diagnostic.CA1806.severity = suggestion
|
||||
|
||||
# CA1822: Mark members as static
|
||||
# Potential false positive around reflection/too much noise
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
# CA1826: Do not use Enumerable method on indexable collections
|
||||
dotnet_diagnostic.CA1826.severity = suggestion
|
||||
|
||||
# CA1859: Use concrete types when possible for improved performance
|
||||
# Involves design considerations
|
||||
dotnet_diagnostic.CA1859.severity = suggestion
|
||||
|
||||
# CA1860: Avoid using 'Enumerable.Any()' extension method
|
||||
dotnet_diagnostic.CA1860.severity = suggestion
|
||||
|
||||
# CA1861: Avoid constant arrays as arguments
|
||||
# Outdated with collection expressions
|
||||
dotnet_diagnostic.CA1861.severity = suggestion
|
||||
|
||||
# CA2007: Consider calling ConfigureAwait on the awaited task
|
||||
dotnet_diagnostic.CA2007.severity = warning
|
||||
|
||||
# CA2016: Forward the 'CancellationToken' parameter to methods
|
||||
# Some overloads are having special handling for debugger
|
||||
dotnet_diagnostic.CA2016.severity = suggestion
|
||||
|
||||
# CA2021: Do not call Enumerable.Cast<T> or Enumerable.OfType<T> with incompatible types
|
||||
# Causing a lot of false positives with generics
|
||||
dotnet_diagnostic.CA2021.severity = none
|
||||
|
||||
# CA2101: Specify marshaling for P/Invoke string arguments
|
||||
# Reports warning for all non-UTF16 usages on DllImport; consider migrating to LibraryImport
|
||||
dotnet_diagnostic.CA2101.severity = none
|
||||
|
||||
# CA2201: Do not raise reserved exception types
|
||||
dotnet_diagnostic.CA2201.severity = warning
|
||||
|
||||
# CA2208: Instantiate argument exceptions correctly
|
||||
dotnet_diagnostic.CA2208.severity = suggestion
|
||||
|
||||
# CA2242: Test for NaN correctly
|
||||
dotnet_diagnostic.CA2242.severity = warning
|
||||
|
||||
# Banned APIs
|
||||
dotnet_diagnostic.RS0030.severity = error
|
||||
|
||||
# Temporarily disable analysing CanBeNull = true in NRT contexts due to mobile issues.
|
||||
# See: https://github.com/ppy/osu/pull/19677
|
||||
dotnet_diagnostic.OSUF001.severity = none
|
|
@ -36,7 +36,7 @@ namespace PerformanceCalculator
|
|||
|
||||
protected T GetJsonFromApi<T>(string request, HttpMethod method = null, Dictionary<string, string> parameters = null)
|
||||
{
|
||||
using var req = new JsonWebRequest<T>($"{Program.ENDPOINT_CONFIGURATION.APIEndpointUrl}/api/v2/{request}");
|
||||
using var req = new JsonWebRequest<T>($"{Program.ENDPOINT_CONFIGURATION.APIUrl}/api/v2/{request}");
|
||||
req.Method = method ?? HttpMethod.Get;
|
||||
req.AddHeader("x-api-version", api_version.ToString(CultureInfo.InvariantCulture));
|
||||
req.AddHeader(System.Net.HttpRequestHeader.Authorization.ToString(), $"Bearer {apiAccessToken}");
|
||||
|
@ -54,7 +54,7 @@ namespace PerformanceCalculator
|
|||
|
||||
private void getAccessToken()
|
||||
{
|
||||
using var req = new JsonWebRequest<dynamic>($"{Program.ENDPOINT_CONFIGURATION.APIEndpointUrl}/oauth/token")
|
||||
using var req = new JsonWebRequest<dynamic>($"{Program.ENDPOINT_CONFIGURATION.APIUrl}/oauth/token")
|
||||
{
|
||||
Method = HttpMethod.Post
|
||||
};
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace PerformanceCalculator.Difficulty
|
|||
{
|
||||
var document = new Document();
|
||||
|
||||
foreach (var error in resultSet.Errors)
|
||||
foreach (string error in resultSet.Errors)
|
||||
document.Children.Add(new Span(error), "\n");
|
||||
if (resultSet.Errors.Count > 0)
|
||||
document.Children.Add("\n");
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace PerformanceCalculator.Difficulty
|
|||
{
|
||||
var document = new Document();
|
||||
|
||||
foreach (var error in resultSet.Errors)
|
||||
foreach (string error in resultSet.Errors)
|
||||
document.Children.Add(new Span(error), "\n");
|
||||
if (resultSet.Errors.Count > 0)
|
||||
document.Children.Add("\n");
|
||||
|
@ -85,7 +85,7 @@ namespace PerformanceCalculator.Difficulty
|
|||
// Headers
|
||||
if (firstResult)
|
||||
{
|
||||
foreach (var column in new[] { "Beatmap", "Mods", "Accuracy score", "Combo score", "Bonus score ratio", "Mod multiplier" })
|
||||
foreach (string column in new[] { "Beatmap", "Mods", "Accuracy score", "Combo score", "Bonus score ratio", "Mod multiplier" })
|
||||
{
|
||||
grid.Columns.Add(GridLength.Auto);
|
||||
grid.Children.Add(new Cell(column));
|
||||
|
@ -121,7 +121,7 @@ namespace PerformanceCalculator.Difficulty
|
|||
var attributes = simulator.Simulate(beatmap, playableBeatmap);
|
||||
|
||||
var conversionInfo = LegacyBeatmapConversionDifficultyInfo.FromBeatmap(playableBeatmap);
|
||||
var modMultiplier = simulator.GetLegacyScoreMultiplier(mods, conversionInfo);
|
||||
double modMultiplier = simulator.GetLegacyScoreMultiplier(mods, conversionInfo);
|
||||
|
||||
return new Result
|
||||
{
|
||||
|
@ -142,9 +142,9 @@ namespace PerformanceCalculator.Difficulty
|
|||
|
||||
var availableMods = ruleset.CreateAllMods().ToList();
|
||||
|
||||
foreach (var modString in Mods)
|
||||
foreach (string modString in Mods)
|
||||
{
|
||||
Mod newMod = availableMods.FirstOrDefault(m => string.Equals(m.Acronym, modString, StringComparison.CurrentCultureIgnoreCase));
|
||||
Mod newMod = availableMods.FirstOrDefault(m => string.Equals(m.Acronym, modString, StringComparison.OrdinalIgnoreCase));
|
||||
if (newMod == null)
|
||||
throw new ArgumentException($"Invalid mod provided: {modString}");
|
||||
|
||||
|
|
|
@ -97,9 +97,9 @@ namespace PerformanceCalculator.Difficulty
|
|||
var availableMods = ruleset.CreateAllMods().ToList();
|
||||
var mods = new List<Mod>();
|
||||
|
||||
foreach (var modString in Mods)
|
||||
foreach (string modString in Mods)
|
||||
{
|
||||
Mod newMod = availableMods.FirstOrDefault(m => string.Equals(m.Acronym, modString, StringComparison.CurrentCultureIgnoreCase));
|
||||
Mod newMod = availableMods.FirstOrDefault(m => string.Equals(m.Acronym, modString, StringComparison.OrdinalIgnoreCase));
|
||||
if (newMod == null)
|
||||
throw new ArgumentException($"Invalid mod provided: {modString}");
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Humanizer;
|
||||
using McMaster.Extensions.CommandLineUtils;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
|
@ -66,7 +66,7 @@ namespace PerformanceCalculator.Difficulty
|
|||
|
||||
foreach (var (settingsSource, propertyInfo) in sourceProperties)
|
||||
{
|
||||
var bindable = propertyInfo.GetValue(mod);
|
||||
object? bindable = propertyInfo.GetValue(mod);
|
||||
|
||||
Debug.Assert(bindable != null);
|
||||
|
||||
|
@ -75,7 +75,7 @@ namespace PerformanceCalculator.Difficulty
|
|||
|
||||
yield return new
|
||||
{
|
||||
Name = propertyInfo.Name.Underscore(),
|
||||
Name = propertyInfo.Name.ToSnakeCase(),
|
||||
Type = getJsonType(netType),
|
||||
Label = settingsSource.Label.ToString(),
|
||||
Description = settingsSource.Description.ToString(),
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace PerformanceCalculator.Leaderboard
|
|||
|
||||
public override void Execute()
|
||||
{
|
||||
var rulesetApiName = LegacyHelper.GetRulesetShortNameFromId(Ruleset ?? 0);
|
||||
string rulesetApiName = LegacyHelper.GetRulesetShortNameFromId(Ruleset ?? 0);
|
||||
var leaderboard = GetJsonFromApi<GetTopUsersResponse>($"rankings/{rulesetApiName}/performance?cursor[page]={LeaderboardPage - 1}");
|
||||
|
||||
var calculatedPlayers = new List<LeaderboardPlayerInfo>();
|
||||
|
@ -78,7 +78,7 @@ namespace PerformanceCalculator.Leaderboard
|
|||
double nonBonusLivePP = liveOrdered.Sum(play => Math.Pow(0.95, index++) * play);
|
||||
|
||||
//todo: implement properly. this is pretty damn wrong.
|
||||
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
double playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
totalLocalPP += playcountBonusPP;
|
||||
|
||||
calculatedPlayers.Add(new LeaderboardPlayerInfo
|
||||
|
@ -94,7 +94,7 @@ namespace PerformanceCalculator.Leaderboard
|
|||
|
||||
if (OutputJson)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(calculatedPlayers);
|
||||
string json = JsonConvert.SerializeObject(calculatedPlayers);
|
||||
|
||||
Console.Write(json);
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Alba.CsConsoleFormat" Version="1.0.0" />
|
||||
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
|
||||
<PackageReference Include="ppy.osu.Game" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2025.227.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace PerformanceCalculator
|
|||
|
||||
var ppAttributeValues = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonConvert.SerializeObject(result.PerformanceAttributes)) ?? new Dictionary<string, object>();
|
||||
foreach (var attrib in ppAttributeValues)
|
||||
document.Children.Add(FormatDocumentLine(attrib.Key.Humanize().ToLower(), FormattableString.Invariant($"{attrib.Value:N2}")));
|
||||
document.Children.Add(FormatDocumentLine(attrib.Key.Humanize().ToLower(CultureInfo.InvariantCulture), FormattableString.Invariant($"{attrib.Value:N2}")));
|
||||
|
||||
AddSectionHeader(document, "Difficulty attributes");
|
||||
|
||||
|
@ -118,9 +118,9 @@ namespace PerformanceCalculator
|
|||
{
|
||||
ConsoleRenderer.RenderDocumentToText(document, new TextRenderTarget(writer), new Rect(0, 0, 250, Size.Infinity));
|
||||
|
||||
var str = writer.GetStringBuilder().ToString();
|
||||
string str = writer.GetStringBuilder().ToString();
|
||||
|
||||
var lines = str.Split('\n');
|
||||
string[] lines = str.Split('\n');
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
lines[i] = lines[i].TrimEnd();
|
||||
str = string.Join('\n', lines);
|
||||
|
@ -143,7 +143,7 @@ namespace PerformanceCalculator
|
|||
|
||||
var mods = new List<Mod>();
|
||||
|
||||
foreach (var acronym in acronyms)
|
||||
foreach (string acronym in acronyms)
|
||||
{
|
||||
APIMod mod = new APIMod { Acronym = acronym };
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace PerformanceCalculator
|
|||
return new ProcessorWorkingBeatmap(fileOrId);
|
||||
}
|
||||
|
||||
if (!int.TryParse(fileOrId, out var beatmapId))
|
||||
if (!int.TryParse(fileOrId, out int beatmapId))
|
||||
throw new ArgumentException("Could not parse provided beatmap ID.");
|
||||
|
||||
string cachePath = Path.Combine("cache", $"{beatmapId}.osu");
|
||||
|
@ -66,7 +66,7 @@ namespace PerformanceCalculator
|
|||
if (!File.Exists(cachePath))
|
||||
{
|
||||
Console.WriteLine($"Downloading {beatmapId}.osu...");
|
||||
new FileWebRequest(cachePath, $"{Program.ENDPOINT_CONFIGURATION.WebsiteRootUrl}/osu/{beatmapId}").Perform();
|
||||
new FileWebRequest(cachePath, $"{Program.ENDPOINT_CONFIGURATION.WebsiteUrl}/osu/{beatmapId}").Perform();
|
||||
}
|
||||
|
||||
return new ProcessorWorkingBeatmap(cachePath, beatmapId);
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace PerformanceCalculator.Profile
|
|||
var displayPlays = new List<UserPlayInfo>();
|
||||
|
||||
var ruleset = LegacyHelper.GetRulesetFromLegacyID(Ruleset ?? 0);
|
||||
var rulesetApiName = LegacyHelper.GetRulesetShortNameFromId(Ruleset ?? 0);
|
||||
string rulesetApiName = LegacyHelper.GetRulesetShortNameFromId(Ruleset ?? 0);
|
||||
|
||||
Console.WriteLine("Getting user data...");
|
||||
var userData = GetJsonFromApi<APIUser>($"users/{ProfileName}/{ruleset.ShortName}");
|
||||
|
@ -81,15 +81,15 @@ namespace PerformanceCalculator.Profile
|
|||
double nonBonusLivePP = liveOrdered.Sum(play => Math.Pow(0.95, index++) * play.LivePP);
|
||||
|
||||
//todo: implement properly. this is pretty damn wrong.
|
||||
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
double playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
totalLocalPP += playcountBonusPP;
|
||||
double totalDiffPP = totalLocalPP - totalLivePP;
|
||||
|
||||
if (OutputJson)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(new
|
||||
string json = JsonConvert.SerializeObject(new
|
||||
{
|
||||
Username = userData.Username,
|
||||
userData.Username,
|
||||
LivePp = totalLivePP,
|
||||
LocalPp = totalLocalPP,
|
||||
PlaycountPp = playcountBonusPP,
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace PerformanceCalculator.Simulate
|
|||
|
||||
private static Dictionary<HitResult, int> generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countGood)
|
||||
{
|
||||
var maxCombo = beatmap.GetMaxCombo();
|
||||
int maxCombo = beatmap.GetMaxCombo();
|
||||
int maxTinyDroplets = beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.NestedHitObjects.OfType<TinyDroplet>().Count());
|
||||
int maxDroplets = beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.NestedHitObjects.OfType<Droplet>().Count()) - maxTinyDroplets;
|
||||
int maxFruits = beatmap.HitObjects.Sum(h => h is Fruit ? 1 : (h as JuiceStream)?.NestedHitObjects.Count(n => n is Fruit) ?? 0);
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace PerformanceCalculator.Simulate
|
|||
private static Dictionary<HitResult, int> generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countOk, int? countGood, int? countGreat)
|
||||
{
|
||||
// One judgement per normal note. Two judgements per hold note (head + tail).
|
||||
var totalHits = beatmap.HitObjects.Count + beatmap.HitObjects.Count(ho => ho is HoldNote);
|
||||
int totalHits = beatmap.HitObjects.Count + beatmap.HitObjects.Count(ho => ho is HoldNote);
|
||||
|
||||
if (countMeh != null || countOk != null || countGood != null || countGreat != null)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ namespace PerformanceCalculator.Simulate
|
|||
}
|
||||
|
||||
// Let Great=Perfect=6, Good=4, Ok=2, Meh=1, Miss=0. The total should be this.
|
||||
var targetTotal = (int)Math.Round(accuracy * totalHits * 6);
|
||||
int targetTotal = (int)Math.Round(accuracy * totalHits * 6);
|
||||
|
||||
// Start by assuming every non miss is a meh
|
||||
// This is how much increase is needed by the rest
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace PerformanceCalculator.Simulate
|
|||
{
|
||||
int countGreat;
|
||||
|
||||
var totalResultCount = beatmap.HitObjects.Count;
|
||||
int totalResultCount = beatmap.HitObjects.Count;
|
||||
|
||||
if (countMeh != null || countGood != null)
|
||||
{
|
||||
|
@ -153,27 +153,26 @@ namespace PerformanceCalculator.Simulate
|
|||
|
||||
protected override double GetAccuracy(IBeatmap beatmap, Dictionary<HitResult, int> statistics)
|
||||
{
|
||||
var countGreat = statistics[HitResult.Great];
|
||||
var countGood = statistics[HitResult.Ok];
|
||||
var countMeh = statistics[HitResult.Meh];
|
||||
var countMiss = statistics[HitResult.Miss];
|
||||
int countGreat = statistics[HitResult.Great];
|
||||
int countGood = statistics[HitResult.Ok];
|
||||
int countMeh = statistics[HitResult.Meh];
|
||||
int countMiss = statistics[HitResult.Miss];
|
||||
|
||||
double total = 6 * countGreat + 2 * countGood + countMeh;
|
||||
double max = 6 * (countGreat + countGood + countMeh + countMiss);
|
||||
|
||||
if (statistics.ContainsKey(HitResult.SliderTailHit))
|
||||
if (statistics.TryGetValue(HitResult.SliderTailHit, out int countSliderTailHit))
|
||||
{
|
||||
var countSliders = beatmap.HitObjects.Count(x => x is Slider);
|
||||
var countSliderTailHit = statistics[HitResult.SliderTailHit];
|
||||
int countSliders = beatmap.HitObjects.Count(x => x is Slider);
|
||||
|
||||
total += 3 * countSliderTailHit;
|
||||
max += 3 * countSliders;
|
||||
}
|
||||
|
||||
if (statistics.ContainsKey(HitResult.LargeTickMiss))
|
||||
if (statistics.TryGetValue(HitResult.LargeTickMiss, out int countLargeTickMiss))
|
||||
{
|
||||
var countLargeTicks = beatmap.HitObjects.Sum(obj => obj.NestedHitObjects.Count(x => x is SliderTick or SliderRepeat));
|
||||
var countLargeTickHit = countLargeTicks - statistics[HitResult.LargeTickMiss];
|
||||
int countLargeTicks = beatmap.HitObjects.Sum(obj => obj.NestedHitObjects.Count(x => x is SliderTick or SliderRepeat));
|
||||
int countLargeTickHit = countLargeTicks - countLargeTickMiss;
|
||||
|
||||
total += 0.6 * countLargeTickHit;
|
||||
max += 0.6 * countLargeTicks;
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace PerformanceCalculator.Simulate
|
|||
var mods = ParseMods(ruleset, Mods, ModOptions);
|
||||
var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
|
||||
|
||||
var beatmapMaxCombo = beatmap.GetMaxCombo();
|
||||
int beatmapMaxCombo = beatmap.GetMaxCombo();
|
||||
var statistics = GenerateHitResults(beatmap, mods);
|
||||
var scoreInfo = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo)
|
||||
{
|
||||
|
|
|
@ -34,7 +34,7 @@ namespace PerformanceCalculator.Simulate
|
|||
|
||||
private static Dictionary<HitResult, int> generateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countGood)
|
||||
{
|
||||
var totalResultCount = beatmap.GetMaxCombo();
|
||||
int totalResultCount = beatmap.GetMaxCombo();
|
||||
|
||||
int countGreat;
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace PerformanceCalculator.Simulate
|
|||
else
|
||||
{
|
||||
// Let Great=2, Good=1, Miss=0. The total should be this.
|
||||
var targetTotal = (int)Math.Round(accuracy * totalResultCount * 2);
|
||||
int targetTotal = (int)Math.Round(accuracy * totalResultCount * 2);
|
||||
|
||||
countGreat = targetTotal - (totalResultCount - countMiss);
|
||||
countGood = totalResultCount - countGreat - countMiss;
|
||||
|
@ -62,10 +62,10 @@ namespace PerformanceCalculator.Simulate
|
|||
|
||||
protected override double GetAccuracy(IBeatmap beatmap, Dictionary<HitResult, int> statistics)
|
||||
{
|
||||
var countGreat = statistics[HitResult.Great];
|
||||
var countGood = statistics[HitResult.Ok];
|
||||
var countMiss = statistics[HitResult.Miss];
|
||||
var total = countGreat + countGood + countMiss;
|
||||
int countGreat = statistics[HitResult.Great];
|
||||
int countGood = statistics[HitResult.Ok];
|
||||
int countMiss = statistics[HitResult.Miss];
|
||||
int total = countGreat + countGood + countMiss;
|
||||
|
||||
return (double)((2 * countGreat) + countGood) / (2 * total);
|
||||
}
|
||||
|
|
|
@ -35,21 +35,21 @@ namespace PerformanceCalculatorGUI
|
|||
{
|
||||
if (token == null)
|
||||
{
|
||||
await getAccessToken();
|
||||
await getAccessToken().ConfigureAwait(false);
|
||||
Debug.Assert(token != null);
|
||||
}
|
||||
|
||||
using var req = new JsonWebRequest<T>($"{ENDPOINT_CONFIGURATION.APIEndpointUrl}/api/v2/{request}");
|
||||
using var req = new JsonWebRequest<T>($"{ENDPOINT_CONFIGURATION.APIUrl}/api/v2/{request}");
|
||||
req.AddHeader("x-api-version", api_version.ToString(CultureInfo.InvariantCulture));
|
||||
req.AddHeader(System.Net.HttpRequestHeader.Authorization.ToString(), $"Bearer {token.AccessToken}");
|
||||
await req.PerformAsync();
|
||||
await req.PerformAsync().ConfigureAwait(false);
|
||||
|
||||
return req.ResponseObject;
|
||||
}
|
||||
|
||||
private async Task getAccessToken()
|
||||
{
|
||||
using var req = new JsonWebRequest<OAuthToken>($"{ENDPOINT_CONFIGURATION.APIEndpointUrl}/oauth/token")
|
||||
using var req = new JsonWebRequest<OAuthToken>($"{ENDPOINT_CONFIGURATION.APIUrl}/oauth/token")
|
||||
{
|
||||
Method = HttpMethod.Post
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ namespace PerformanceCalculatorGUI
|
|||
req.AddParameter("client_secret", clientSecretBindable.Value);
|
||||
req.AddParameter("grant_type", "client_credentials");
|
||||
req.AddParameter("scope", "public");
|
||||
await req.PerformAsync();
|
||||
await req.PerformAsync().ConfigureAwait(false);
|
||||
|
||||
token = req.ResponseObject;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,9 @@ namespace PerformanceCalculatorGUI.Components
|
|||
|
||||
currentData = data;
|
||||
|
||||
var split = data.Split('\n');
|
||||
string[] split = data.Split('\n');
|
||||
|
||||
foreach (var line in split)
|
||||
foreach (string line in split)
|
||||
textContainer.Add(new OsuSpriteText { Text = line });
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = colourProvider.Light1,
|
||||
Text = Score.PositionChange.Value.ToString()
|
||||
Text = $"{Score.PositionChange.Value:+0;-0;-}"
|
||||
}
|
||||
},
|
||||
new Container
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
|
||||
protected sealed override CountryCode GetCountryCode(LeaderboardUser item) => item.User.CountryCode;
|
||||
|
||||
protected sealed override Drawable CreateFlagContent(LeaderboardUser item)
|
||||
protected sealed override Drawable[] CreateFlagContent(LeaderboardUser item)
|
||||
{
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE, italics: true))
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
TextAnchor = Anchor.CentreLeft
|
||||
};
|
||||
username.AddUserLink(item.User);
|
||||
return username;
|
||||
return [username];
|
||||
}
|
||||
|
||||
private partial class DifferenceText : OsuSpriteText
|
||||
|
|
|
@ -5,14 +5,15 @@ using osu.Framework.Graphics.Sprites;
|
|||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps.Drawables.Cards;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Components;
|
||||
|
||||
public partial class ScreenSelectionButtonIcon : IconPill
|
||||
namespace PerformanceCalculatorGUI.Components
|
||||
{
|
||||
public ScreenSelectionButtonIcon(IconUsage? icon = null)
|
||||
: base(icon ?? FontAwesome.Solid.List)
|
||||
public partial class ScreenSelectionButtonIcon : IconPill
|
||||
{
|
||||
}
|
||||
public ScreenSelectionButtonIcon(IconUsage? icon = null)
|
||||
: base(icon ?? FontAwesome.Solid.List)
|
||||
{
|
||||
}
|
||||
|
||||
public override LocalisableString TooltipText => string.Empty;
|
||||
public override LocalisableString TooltipText => string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
{
|
||||
// this is ugly, but it works
|
||||
var graphToggleBindable = new Bindable<bool>();
|
||||
var graphNum = i;
|
||||
int graphNum = i;
|
||||
graphToggleBindable.BindValueChanged(state =>
|
||||
{
|
||||
if (state.NewValue)
|
||||
|
@ -111,7 +111,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
Width = 200,
|
||||
Current = { BindTarget = graphToggleBindable, Default = true, Value = true },
|
||||
LabelText = skills[i].GetType().Name,
|
||||
TextColour = skillColours[i]
|
||||
TextColour = skillColours[i % skillColours.Length]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -186,7 +186,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
|
||||
private void addStrainBars(Skill[] skills, List<float[]> strainLists)
|
||||
{
|
||||
var strainMaxValue = strainLists.Max(list => list.Max());
|
||||
float strainMaxValue = strainLists.Max(list => list.Max());
|
||||
|
||||
for (int i = 0; i < skills.Length; i++)
|
||||
{
|
||||
|
@ -196,7 +196,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = graphAlpha,
|
||||
Colour = skillColours[i],
|
||||
Colour = skillColours[i % skillColours.Length],
|
||||
Child = new StrainBarGraph
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
@ -223,7 +223,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
for (int i = 0; i < nBars; i++)
|
||||
{
|
||||
var strainTime = TimeSpan.FromMilliseconds(TimeUntilFirstStrain.Value + lastStrainTime * i / nBars);
|
||||
var tooltipText = $"~{strainTime:mm\\:ss\\.ff}";
|
||||
string tooltipText = $"~{strainTime:mm\\:ss\\.ff}";
|
||||
tooltipList.Add(tooltipText);
|
||||
}
|
||||
|
||||
|
@ -248,13 +248,13 @@ namespace PerformanceCalculatorGUI.Components
|
|||
|
||||
foreach (var skill in skills)
|
||||
{
|
||||
var strains = ((StrainSkill)skill).GetCurrentStrainPeaks().ToArray();
|
||||
double[] strains = ((StrainSkill)skill).GetCurrentStrainPeaks().ToArray();
|
||||
|
||||
var skillStrainList = new List<float>();
|
||||
|
||||
for (int i = 0; i < strains.Length; i++)
|
||||
{
|
||||
var strain = strains[i];
|
||||
double strain = strains[i];
|
||||
skillStrainList.Add(((float)strain));
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
{
|
||||
Clear();
|
||||
|
||||
foreach (var val in value)
|
||||
foreach (float val in value)
|
||||
{
|
||||
float length = MaxValue ?? value.Max();
|
||||
if (length != 0)
|
||||
|
@ -324,7 +324,7 @@ namespace PerformanceCalculatorGUI.Components
|
|||
{
|
||||
Clear();
|
||||
|
||||
foreach (var tooltip in value)
|
||||
foreach (string tooltip in value)
|
||||
{
|
||||
float size = value.Count();
|
||||
if (size != 0)
|
||||
|
|
|
@ -11,15 +11,13 @@ namespace PerformanceCalculatorGUI.Components.TextBoxes
|
|||
{
|
||||
private partial class FractionalNumberBox : OsuTextBox
|
||||
{
|
||||
protected override bool AllowIme => false;
|
||||
|
||||
protected override bool CanAddCharacter(char character) => char.IsAsciiDigit(character) || character == CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator[0];
|
||||
|
||||
protected override void OnUserTextAdded(string added)
|
||||
{
|
||||
base.OnUserTextAdded(added);
|
||||
|
||||
var textToParse = Text;
|
||||
string textToParse = Text;
|
||||
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
|
@ -41,7 +39,7 @@ namespace PerformanceCalculatorGUI.Components.TextBoxes
|
|||
|
||||
protected override void OnUserTextRemoved(string removed)
|
||||
{
|
||||
var textToParse = Text;
|
||||
string textToParse = Text;
|
||||
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace PerformanceCalculatorGUI.Components.TextBoxes
|
|||
{
|
||||
base.OnUserTextAdded(added);
|
||||
|
||||
var textToParse = Text;
|
||||
string textToParse = Text;
|
||||
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ namespace PerformanceCalculatorGUI.Components.TextBoxes
|
|||
|
||||
protected override void OnUserTextRemoved(string removed)
|
||||
{
|
||||
var textToParse = Text;
|
||||
string textToParse = Text;
|
||||
|
||||
if (string.IsNullOrEmpty(Text))
|
||||
{
|
||||
|
|
|
@ -62,12 +62,6 @@ namespace PerformanceCalculatorGUI.Components
|
|||
Action = () => { host.OpenUrlExternally($"https://osu.ppy.sh/u/{User.Id}"); };
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
Status.UnbindAll();
|
||||
Activity.UnbindAll();
|
||||
}
|
||||
|
||||
protected override Drawable CreateLayout()
|
||||
{
|
||||
var layout = new Container
|
||||
|
@ -163,7 +157,14 @@ namespace PerformanceCalculatorGUI.Components
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// this is like COMPLETELY screwed but is required to have this not die of death because `ExtendedUserPanel` expects `LastVisitMessage` to not be null
|
||||
// and that is created and assigned to by `CreateStatusMessage()`.
|
||||
// the card API is SHOCKING and needs to be taken behind the barn and old yeller'd five years ago.
|
||||
// it is NOT A GOOD IDEA to have A PROTECTED OVERRIDABLE METHOD THAT CAN MAKE READING OTHER PROTECTED MEMBERS DANGEROUS!!!!
|
||||
// or that A PROTECTED METHOD which you can FORGET TO CALL should be RESPONSIBLE FOR SETTING UP A PROTECTED FIELD!!!!
|
||||
CreateStatusMessage(false).With(wtf => wtf.Alpha = 0),
|
||||
CreateStatusIcon().With(wtf => wtf.Alpha = 0),
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -10,23 +10,24 @@ using osu.Game.Rulesets.Difficulty.Preprocessing;
|
|||
using osu.Game.Rulesets.Difficulty.Skills;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
|
||||
namespace PerformanceCalculatorGUI;
|
||||
|
||||
public class ExtendedCatchDifficultyCalculator : CatchDifficultyCalculator, IExtendedDifficultyCalculator
|
||||
namespace PerformanceCalculatorGUI
|
||||
{
|
||||
private Skill[] skills;
|
||||
|
||||
public ExtendedCatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
public class ExtendedCatchDifficultyCalculator : CatchDifficultyCalculator, IExtendedDifficultyCalculator
|
||||
{
|
||||
}
|
||||
private Skill[] skills;
|
||||
|
||||
public Skill[] GetSkills() => skills;
|
||||
public DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate) => CreateDifficultyHitObjects(beatmap, clockRate).ToArray();
|
||||
public ExtendedCatchDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
this.skills = skills;
|
||||
return base.CreateDifficultyAttributes(beatmap, mods, skills, clockRate);
|
||||
public Skill[] GetSkills() => skills;
|
||||
public DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate) => CreateDifficultyHitObjects(beatmap, clockRate).ToArray();
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
this.skills = skills;
|
||||
return base.CreateDifficultyAttributes(beatmap, mods, skills, clockRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,23 +10,24 @@ using osu.Game.Rulesets.Difficulty.Skills;
|
|||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Difficulty;
|
||||
|
||||
namespace PerformanceCalculatorGUI;
|
||||
|
||||
public class ExtendedOsuDifficultyCalculator : OsuDifficultyCalculator, IExtendedDifficultyCalculator
|
||||
namespace PerformanceCalculatorGUI
|
||||
{
|
||||
private Skill[] skills;
|
||||
|
||||
public ExtendedOsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
public class ExtendedOsuDifficultyCalculator : OsuDifficultyCalculator, IExtendedDifficultyCalculator
|
||||
{
|
||||
}
|
||||
private Skill[] skills;
|
||||
|
||||
public Skill[] GetSkills() => skills;
|
||||
public DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate) => CreateDifficultyHitObjects(beatmap, clockRate).ToArray();
|
||||
public ExtendedOsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
this.skills = skills;
|
||||
return base.CreateDifficultyAttributes(beatmap, mods, skills, clockRate);
|
||||
public Skill[] GetSkills() => skills;
|
||||
public DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate) => CreateDifficultyHitObjects(beatmap, clockRate).ToArray();
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
this.skills = skills;
|
||||
return base.CreateDifficultyAttributes(beatmap, mods, skills, clockRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,23 +10,24 @@ using osu.Game.Rulesets.Difficulty.Skills;
|
|||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty;
|
||||
|
||||
namespace PerformanceCalculatorGUI;
|
||||
|
||||
public class ExtendedTaikoDifficultyCalculator : TaikoDifficultyCalculator, IExtendedDifficultyCalculator
|
||||
namespace PerformanceCalculatorGUI
|
||||
{
|
||||
private Skill[] skills;
|
||||
|
||||
public ExtendedTaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
public class ExtendedTaikoDifficultyCalculator : TaikoDifficultyCalculator, IExtendedDifficultyCalculator
|
||||
{
|
||||
}
|
||||
private Skill[] skills;
|
||||
|
||||
public Skill[] GetSkills() => skills;
|
||||
public DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate) => CreateDifficultyHitObjects(beatmap, clockRate).ToArray();
|
||||
public ExtendedTaikoDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap)
|
||||
: base(ruleset, beatmap)
|
||||
{
|
||||
}
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
this.skills = skills;
|
||||
return base.CreateDifficultyAttributes(beatmap, mods, skills, clockRate);
|
||||
public Skill[] GetSkills() => skills;
|
||||
public DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate) => CreateDifficultyHitObjects(beatmap, clockRate).ToArray();
|
||||
|
||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||
{
|
||||
this.skills = skills;
|
||||
return base.CreateDifficultyAttributes(beatmap, mods, skills, clockRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,11 @@ using osu.Game.Beatmaps;
|
|||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Skills;
|
||||
|
||||
namespace PerformanceCalculatorGUI;
|
||||
|
||||
public interface IExtendedDifficultyCalculator
|
||||
namespace PerformanceCalculatorGUI
|
||||
{
|
||||
Skill[] GetSkills();
|
||||
DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate);
|
||||
public interface IExtendedDifficultyCalculator
|
||||
{
|
||||
Skill[] GetSkills();
|
||||
DifficultyHitObject[] GetDifficultyHitObjects(IBeatmap beatmap, double clockRate);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2024.1023.0" />
|
||||
<PackageReference Include="ppy.osu.Game" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Osu" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Taiko" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Catch" Version="2025.227.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Rulesets.Mania" Version="2025.227.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace PerformanceCalculatorGUI
|
|||
return new ProcessorWorkingBeatmap(fileOrId, null, audioManager);
|
||||
}
|
||||
|
||||
if (!int.TryParse(fileOrId, out var beatmapId))
|
||||
if (!int.TryParse(fileOrId, out int beatmapId))
|
||||
throw new ArgumentException("Could not parse provided beatmap ID.");
|
||||
|
||||
cachePath = Path.Combine(cachePath, $"{beatmapId}.osu");
|
||||
|
@ -77,7 +77,7 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
try
|
||||
{
|
||||
new FileWebRequest(cachePath, $"{APIManager.ENDPOINT_CONFIGURATION.WebsiteRootUrl}/osu/{beatmapId}").Perform();
|
||||
new FileWebRequest(cachePath, $"{APIManager.ENDPOINT_CONFIGURATION.WebsiteUrl}/osu/{beatmapId}").Perform();
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
|
|
|
@ -3,10 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Catch;
|
||||
|
@ -19,7 +16,6 @@ using osu.Game.Rulesets.Osu.Objects;
|
|||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Skinning;
|
||||
|
||||
namespace PerformanceCalculatorGUI
|
||||
{
|
||||
|
@ -81,7 +77,7 @@ namespace PerformanceCalculatorGUI
|
|||
{
|
||||
int countGreat;
|
||||
|
||||
var totalResultCount = beatmap.HitObjects.Count;
|
||||
int totalResultCount = beatmap.HitObjects.Count;
|
||||
|
||||
if (countMeh != null || countGood != null)
|
||||
{
|
||||
|
@ -172,7 +168,7 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
private static Dictionary<HitResult, int> generateTaikoHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countGood)
|
||||
{
|
||||
var totalResultCount = beatmap.HitObjects.OfType<Hit>().Count();
|
||||
int totalResultCount = beatmap.HitObjects.OfType<Hit>().Count();
|
||||
|
||||
int countGreat;
|
||||
|
||||
|
@ -183,7 +179,7 @@ namespace PerformanceCalculatorGUI
|
|||
else
|
||||
{
|
||||
// Let Great=2, Good=1, Miss=0. The total should be this.
|
||||
var targetTotal = (int)Math.Round(accuracy * totalResultCount * 2);
|
||||
int targetTotal = (int)Math.Round(accuracy * totalResultCount * 2);
|
||||
|
||||
countGreat = targetTotal - (totalResultCount - countMiss);
|
||||
countGood = totalResultCount - countGreat - countMiss;
|
||||
|
@ -200,7 +196,7 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
private static Dictionary<HitResult, int> generateCatchHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood)
|
||||
{
|
||||
var maxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType<JuiceStream>().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet));
|
||||
int maxCombo = beatmap.HitObjects.Count(h => h is Fruit) + beatmap.HitObjects.OfType<JuiceStream>().SelectMany(j => j.NestedHitObjects).Count(h => !(h is TinyDroplet));
|
||||
|
||||
int maxTinyDroplets = beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.NestedHitObjects.OfType<TinyDroplet>().Count());
|
||||
int maxDroplets = beatmap.HitObjects.OfType<JuiceStream>().Sum(s => s.NestedHitObjects.OfType<Droplet>().Count()) - maxTinyDroplets;
|
||||
|
@ -231,14 +227,14 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
private static Dictionary<HitResult, int> generateManiaHitResults(double accuracy, IBeatmap beatmap, int countMiss)
|
||||
{
|
||||
var totalResultCount = beatmap.HitObjects.Count;
|
||||
int totalResultCount = beatmap.HitObjects.Count;
|
||||
|
||||
// Let Great=6, Good=2, Meh=1, Miss=0. The total should be this.
|
||||
var targetTotal = (int)Math.Round(accuracy * totalResultCount * 6);
|
||||
int targetTotal = (int)Math.Round(accuracy * totalResultCount * 6);
|
||||
|
||||
// Start by assuming every non miss is a meh
|
||||
// This is how much increase is needed by greats and goods
|
||||
var delta = targetTotal - (totalResultCount - countMiss);
|
||||
int delta = targetTotal - (totalResultCount - countMiss);
|
||||
|
||||
// Each great increases total by 5 (great-meh=5)
|
||||
int countGreat = delta / 5;
|
||||
|
@ -272,27 +268,26 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
private static double getOsuAccuracy(IBeatmap beatmap, Dictionary<HitResult, int> statistics)
|
||||
{
|
||||
var countGreat = statistics[HitResult.Great];
|
||||
var countGood = statistics[HitResult.Ok];
|
||||
var countMeh = statistics[HitResult.Meh];
|
||||
var countMiss = statistics[HitResult.Miss];
|
||||
int countGreat = statistics[HitResult.Great];
|
||||
int countGood = statistics[HitResult.Ok];
|
||||
int countMeh = statistics[HitResult.Meh];
|
||||
int countMiss = statistics[HitResult.Miss];
|
||||
|
||||
double total = 6 * countGreat + 2 * countGood + countMeh;
|
||||
double max = 6 * (countGreat + countGood + countMeh + countMiss);
|
||||
|
||||
if (statistics.ContainsKey(HitResult.SliderTailHit))
|
||||
if (statistics.TryGetValue(HitResult.SliderTailHit, out int countSliderTailHit))
|
||||
{
|
||||
var countSliders = beatmap.HitObjects.Count(x => x is Slider);
|
||||
var countSliderTailHit = statistics[HitResult.SliderTailHit];
|
||||
int countSliders = beatmap.HitObjects.Count(x => x is Slider);
|
||||
|
||||
total += 3 * countSliderTailHit;
|
||||
max += 3 * countSliders;
|
||||
}
|
||||
|
||||
if (statistics.ContainsKey(HitResult.LargeTickMiss))
|
||||
if (statistics.TryGetValue(HitResult.LargeTickMiss, out int countLargeTicksMiss))
|
||||
{
|
||||
var countLargeTicks = beatmap.HitObjects.Sum(obj => obj.NestedHitObjects.Count(x => x is SliderTick or SliderRepeat));
|
||||
var countLargeTickHit = countLargeTicks - statistics[HitResult.LargeTickMiss];
|
||||
int countLargeTicks = beatmap.HitObjects.Sum(obj => obj.NestedHitObjects.Count(x => x is SliderTick or SliderRepeat));
|
||||
int countLargeTickHit = countLargeTicks - countLargeTicksMiss;
|
||||
|
||||
total += 0.6 * countLargeTickHit;
|
||||
max += 0.6 * countLargeTicks;
|
||||
|
@ -303,10 +298,10 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
private static double getTaikoAccuracy(Dictionary<HitResult, int> statistics)
|
||||
{
|
||||
var countGreat = statistics[HitResult.Great];
|
||||
var countGood = statistics[HitResult.Ok];
|
||||
var countMiss = statistics[HitResult.Miss];
|
||||
var total = countGreat + countGood + countMiss;
|
||||
int countGreat = statistics[HitResult.Great];
|
||||
int countGood = statistics[HitResult.Ok];
|
||||
int countMiss = statistics[HitResult.Miss];
|
||||
int total = countGreat + countGood + countMiss;
|
||||
|
||||
return (double)((2 * countGreat) + countGood) / (2 * total);
|
||||
}
|
||||
|
@ -321,35 +316,17 @@ namespace PerformanceCalculatorGUI
|
|||
|
||||
private static double getManiaAccuracy(Dictionary<HitResult, int> statistics)
|
||||
{
|
||||
var countPerfect = statistics[HitResult.Perfect];
|
||||
var countGreat = statistics[HitResult.Great];
|
||||
var countGood = statistics[HitResult.Good];
|
||||
var countOk = statistics[HitResult.Ok];
|
||||
var countMeh = statistics[HitResult.Meh];
|
||||
var countMiss = statistics[HitResult.Miss];
|
||||
var total = countPerfect + countGreat + countGood + countOk + countMeh + countMiss;
|
||||
int countPerfect = statistics[HitResult.Perfect];
|
||||
int countGreat = statistics[HitResult.Great];
|
||||
int countGood = statistics[HitResult.Good];
|
||||
int countOk = statistics[HitResult.Ok];
|
||||
int countMeh = statistics[HitResult.Meh];
|
||||
int countMiss = statistics[HitResult.Miss];
|
||||
int total = countPerfect + countGreat + countGood + countOk + countMeh + countMiss;
|
||||
|
||||
return (double)
|
||||
((6 * (countPerfect + countGreat)) + (4 * countGood) + (2 * countOk) + countMeh) /
|
||||
(6 * total);
|
||||
}
|
||||
|
||||
private class EmptyWorkingBeatmap : WorkingBeatmap
|
||||
{
|
||||
public EmptyWorkingBeatmap()
|
||||
: base(new BeatmapInfo(), null)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IBeatmap GetBeatmap() => throw new NotImplementedException();
|
||||
|
||||
public override Texture GetBackground() => throw new NotImplementedException();
|
||||
|
||||
protected override Track GetBeatmapTrack() => throw new NotImplementedException();
|
||||
|
||||
protected override ISkin GetSkin() => throw new NotImplementedException();
|
||||
|
||||
public override Stream GetStream(string storagePath) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
Schedule(() => loadingLayer.Text.Value = "Getting leaderboard...");
|
||||
|
||||
var leaderboard = await apiManager.GetJsonFromApi<APIScoresCollection>($@"beatmaps/{beatmapIdTextBox.Current.Value}/scores?scope=global&mode={ruleset.Value.ShortName}");
|
||||
var leaderboard = await apiManager.GetJsonFromApi<APIScoresCollection>($@"beatmaps/{beatmapIdTextBox.Current.Value}/scores?scope=global&mode={ruleset.Value.ShortName}").ConfigureAwait(false);
|
||||
|
||||
var plays = new List<SoloScoreInfo>();
|
||||
|
||||
|
@ -236,9 +236,11 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
var difficultyAttributes = difficultyCalculator.Calculate(mods);
|
||||
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();
|
||||
if (performanceCalculator == null)
|
||||
continue;
|
||||
|
||||
var perfAttributes = await performanceCalculator?.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token)!;
|
||||
score.PP = perfAttributes?.Total ?? 0.0;
|
||||
var perfAttributes = await performanceCalculator.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token).ConfigureAwait(false);
|
||||
score.PP = perfAttributes.Total;
|
||||
|
||||
plays.Add(score);
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
Schedule(() => loadingLayer.Text.Value = "Getting leaderboard...");
|
||||
|
||||
var leaderboard = await apiManager.GetJsonFromApi<GetTopUsersResponse>($"rankings/{ruleset.Value.ShortName}/performance?cursor[page]={pageTextBox.Value.Value - 1}");
|
||||
var leaderboard = await apiManager.GetJsonFromApi<GetTopUsersResponse>($"rankings/{ruleset.Value.ShortName}/performance?cursor[page]={pageTextBox.Value.Value - 1}").ConfigureAwait(false);
|
||||
|
||||
var calculatedPlayers = new List<LeaderboardUser>();
|
||||
var calculatedScores = new List<ExtendedScore>();
|
||||
|
@ -253,7 +253,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
Schedule(() => loadingLayer.Text.Value = $"Calculating {player.User.Username} top scores...");
|
||||
|
||||
var playerData = await calculatePlayer(player, token);
|
||||
var playerData = await calculatePlayer(player, token).ConfigureAwait(false);
|
||||
|
||||
calculatedPlayers.Add(new LeaderboardUser
|
||||
{
|
||||
|
@ -301,7 +301,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
var plays = new List<ExtendedScore>();
|
||||
|
||||
var apiScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.User.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit=100");
|
||||
var apiScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.User.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit=100").ConfigureAwait(false);
|
||||
|
||||
var rulesetInstance = ruleset.Value.CreateInstance();
|
||||
|
||||
|
@ -323,7 +323,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
var difficultyAttributes = difficultyCalculator.Calculate(mods);
|
||||
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();
|
||||
|
||||
var livePp = score.PP ?? 0.0;
|
||||
double? livePp = score.PP;
|
||||
var perfAttributes = performanceCalculator?.Calculate(parsedScore.ScoreInfo, difficultyAttributes);
|
||||
score.PP = perfAttributes?.Total ?? 0.0;
|
||||
|
||||
|
@ -346,17 +346,17 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
catch (OperationCanceledException) { }
|
||||
|
||||
var localOrdered = plays.OrderByDescending(x => x.SoloScore.PP).ToList();
|
||||
var liveOrdered = plays.OrderByDescending(x => x.LivePP).ToList();
|
||||
var liveOrdered = plays.OrderByDescending(x => x.LivePP ?? 0.0).ToList();
|
||||
|
||||
int index = 0;
|
||||
decimal totalLocalPP = (decimal)(localOrdered.Select(x => x.SoloScore.PP).Sum(play => Math.Pow(0.95, index++) * play) ?? 0.0);
|
||||
decimal totalLivePP = player.PP ?? (decimal)0.0;
|
||||
|
||||
index = 0;
|
||||
decimal nonBonusLivePP = (decimal)liveOrdered.Select(x => x.LivePP).Sum(play => Math.Pow(0.95, index++) * play);
|
||||
decimal nonBonusLivePP = (decimal)liveOrdered.Select(x => x.LivePP ?? 0.0).Sum(play => Math.Pow(0.95, index++) * play);
|
||||
|
||||
//todo: implement properly. this is pretty damn wrong.
|
||||
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
decimal playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
totalLocalPP += playcountBonusPP;
|
||||
|
||||
return new UserLeaderboardData
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Difficulty.Preprocessing;
|
||||
|
@ -17,8 +19,10 @@ using osu.Game.Rulesets.Mods;
|
|||
using osu.Game.Rulesets.Osu.Difficulty.Evaluators;
|
||||
using osu.Game.Rulesets.Osu.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Evaluators;
|
||||
using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osuTK;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
||||
|
@ -28,6 +32,9 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
[Resolved]
|
||||
private Bindable<IReadOnlyList<Mod>> appliedMods { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private Track track { get; set; }
|
||||
|
||||
private SpriteText hitObjectTypeText;
|
||||
|
||||
private FillFlowContainer flowContainer;
|
||||
|
@ -72,7 +79,7 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
Colour = colors.Background6,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
hitObjectTypeText = new SpriteText
|
||||
hitObjectTypeText = new OsuSpriteText
|
||||
{
|
||||
Font = new FontUsage(size: 30),
|
||||
Padding = new MarginPadding(10)
|
||||
|
@ -120,25 +127,26 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
|
||||
private void drawOsuValues(OsuDifficultyHitObject hitObject)
|
||||
{
|
||||
var hidden = appliedMods.Value.Any(x => x is ModHidden);
|
||||
bool hidden = appliedMods.Value.Any(x => x is ModHidden);
|
||||
flowContainer.AddRange(new[]
|
||||
{
|
||||
new ObjectInspectorDifficultyValue("Position", (hitObject.BaseObject as OsuHitObject)!.StackedPosition),
|
||||
new ObjectInspectorDifficultyValue("Strain Time", hitObject.StrainTime),
|
||||
new ObjectInspectorDifficultyValue("Doubletapness", hitObject.GetDoubletapness((OsuDifficultyHitObject)hitObject.Next(0))),
|
||||
new ObjectInspectorDifficultyValue("Lazy Jump Dist", hitObject.LazyJumpDistance),
|
||||
new ObjectInspectorDifficultyValue("Min Jump Dist", hitObject.MinimumJumpDistance),
|
||||
new ObjectInspectorDifficultyValue("Min Jump Time", hitObject.MinimumJumpTime),
|
||||
|
||||
new ObjectInspectorDifficultyValue("Aim Difficulty", AimEvaluator.EvaluateDifficultyOf(hitObject, true)),
|
||||
new ObjectInspectorDifficultyValue("Aim Difficulty (w/o sliders)", AimEvaluator.EvaluateDifficultyOf(hitObject, false)),
|
||||
new ObjectInspectorDifficultyValue("Speed Difficulty", SpeedEvaluator.EvaluateDifficultyOf(hitObject)),
|
||||
new ObjectInspectorDifficultyValue("Rhythm Diff", RhythmEvaluator.EvaluateDifficultyOf(hitObject)),
|
||||
new ObjectInspectorDifficultyValue("Speed Difficulty", SpeedEvaluator.EvaluateDifficultyOf(hitObject, appliedMods.Value)),
|
||||
new ObjectInspectorDifficultyValue("Rhythm Diff", osu.Game.Rulesets.Osu.Difficulty.Evaluators.RhythmEvaluator.EvaluateDifficultyOf(hitObject)),
|
||||
new ObjectInspectorDifficultyValue(hidden ? "FLHD Difficulty" : "Flashlight Diff", FlashlightEvaluator.EvaluateDifficultyOf(hitObject, hidden)),
|
||||
});
|
||||
|
||||
if (hitObject.Angle is not null)
|
||||
flowContainer.Add(new ObjectInspectorDifficultyValue("Angle", double.RadiansToDegrees(hitObject.Angle.Value)));
|
||||
|
||||
flowContainer.Add(new ObjectInspectorDifficultyValue("Lazy Jump Dist", hitObject.LazyJumpDistance));
|
||||
flowContainer.Add(new ObjectInspectorDifficultyValue("Min Jump Dist", hitObject.MinimumJumpDistance));
|
||||
flowContainer.Add(new ObjectInspectorDifficultyValue("Min Jump Time", hitObject.MinimumJumpTime));
|
||||
|
||||
if (hitObject.BaseObject is Slider)
|
||||
{
|
||||
flowContainer.AddRange(new Drawable[]
|
||||
|
@ -158,14 +166,27 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
|
||||
private void drawTaikoValues(TaikoDifficultyHitObject hitObject)
|
||||
{
|
||||
double rhythmDifficulty =
|
||||
osu.Game.Rulesets.Taiko.Difficulty.Evaluators.RhythmEvaluator.EvaluateDifficultyOf(hitObject, 2 * hitObject.BaseObject.HitWindows.WindowFor(HitResult.Great) / track.Rate);
|
||||
|
||||
flowContainer.AddRange(new[]
|
||||
{
|
||||
new ObjectInspectorDifficultyValue("Delta Time", hitObject.DeltaTime),
|
||||
new ObjectInspectorDifficultyValue("Effective BPM", hitObject.EffectiveBPM),
|
||||
new ObjectInspectorDifficultyValue("Rhythm Ratio", hitObject.RhythmData.Ratio),
|
||||
new ObjectInspectorDifficultyValue("Colour Difficulty", ColourEvaluator.EvaluateDifficultyOf(hitObject)),
|
||||
new ObjectInspectorDifficultyValue("Stamina Difficulty", StaminaEvaluator.EvaluateDifficultyOf(hitObject)),
|
||||
new ObjectInspectorDifficultyValue("Rhythm Difficulty", hitObject.Rhythm.Difficulty),
|
||||
new ObjectInspectorDifficultyValue("Rhythm Ratio", hitObject.Rhythm.Ratio),
|
||||
new ObjectInspectorDifficultyValue("Rhythm Difficulty", rhythmDifficulty),
|
||||
});
|
||||
|
||||
if (hitObject.BaseObject is Hit hit)
|
||||
{
|
||||
flowContainer.AddRange(new[]
|
||||
{
|
||||
new ObjectInspectorDifficultyValue($"Mono ({hit.Type}) Index", hitObject.MonoIndex),
|
||||
new ObjectInspectorDifficultyValue("Note Index", hitObject.NoteIndex),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void drawCatchValues(CatchDifficultyHitObject hitObject)
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
clock = new EditorClock(playableBeatmap, beatDivisor);
|
||||
clock.ChangeSource(processorBeatmap.Track);
|
||||
dependencies.CacheAs(clock);
|
||||
dependencies.CacheAs(processorBeatmap.Track);
|
||||
|
||||
editorBeatmap = new EditorBeatmap(playableBeatmap);
|
||||
dependencies.CacheAs(editorBeatmap);
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
|
||||
namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
||||
|
@ -45,12 +45,12 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
{
|
||||
new Drawable[]
|
||||
{
|
||||
new SpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = label,
|
||||
Font = OsuFont.GetFont(weight: FontWeight.SemiBold)
|
||||
},
|
||||
new SpriteText
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
|
|
|
@ -90,7 +90,7 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
|
||||
using (hitObject.BeginAbsoluteSequence(hitObject.StartTimeBindable.Value))
|
||||
{
|
||||
var hitObjectDuration = hitObject.HitObject.GetEndTime() - hitObject.StartTimeBindable.Value;
|
||||
double hitObjectDuration = hitObject.HitObject.GetEndTime() - hitObject.StartTimeBindable.Value;
|
||||
|
||||
hitObject.Delay(hitObjectDuration)
|
||||
.FadeTo(0.25f, 200f, Easing.Out)
|
||||
|
|
|
@ -67,6 +67,8 @@ namespace PerformanceCalculatorGUI.Screens.ObjectInspection
|
|||
{
|
||||
}
|
||||
|
||||
protected override bool TryMoveBlueprints(DragEvent e, IList<(SelectionBlueprint<HitObject> blueprint, Vector2[] originalSnapPositions)> blueprints) => false;
|
||||
|
||||
protected partial class TimelineSelectionBlueprintContainer : SelectionBlueprintContainer
|
||||
{
|
||||
protected override Container<SelectionBlueprint<HitObject>> Content { get; }
|
||||
|
|
|
@ -284,7 +284,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
Schedule(() => loadingLayer.Text.Value = $"Getting {username} user data...");
|
||||
|
||||
var player = await apiManager.GetJsonFromApi<APIUser>($"users/{username}/{ruleset.Value.ShortName}");
|
||||
var player = await apiManager.GetJsonFromApi<APIUser>($"users/{username}/{ruleset.Value.ShortName}").ConfigureAwait(false);
|
||||
players.Add(player);
|
||||
currentUsers = currentUsers.Append(player.Username).ToArray();
|
||||
|
||||
|
@ -302,12 +302,12 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
|
||||
Schedule(() => loadingLayer.Text.Value = $"Calculating {player.Username} top scores...");
|
||||
|
||||
var apiScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit=100");
|
||||
var apiScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/best?mode={ruleset.Value.ShortName}&limit=100").ConfigureAwait(false);
|
||||
|
||||
if (includePinnedCheckbox.Current.Value)
|
||||
{
|
||||
var pinnedScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/pinned?mode={ruleset.Value.ShortName}&limit=100");
|
||||
apiScores = apiScores.Concat(pinnedScores.Where(p => !apiScores.Any(b => b.ID == p.ID))).ToList();
|
||||
var pinnedScores = await apiManager.GetJsonFromApi<List<SoloScoreInfo>>($"users/{player.OnlineID}/scores/pinned?mode={ruleset.Value.ShortName}&limit=100").ConfigureAwait(false);
|
||||
apiScores = apiScores.Concat(pinnedScores.Where(p => !apiScores.Any(b => b.ID == p.ID)).ToArray()).ToList();
|
||||
}
|
||||
|
||||
foreach (var score in apiScores)
|
||||
|
@ -328,10 +328,12 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
var difficultyCalculator = rulesetInstance.CreateDifficultyCalculator(working);
|
||||
var difficultyAttributes = difficultyCalculator.Calculate(mods);
|
||||
var performanceCalculator = rulesetInstance.CreatePerformanceCalculator();
|
||||
if (performanceCalculator == null)
|
||||
continue;
|
||||
|
||||
double? livePp = score.PP;
|
||||
var perfAttributes = await performanceCalculator?.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token)!;
|
||||
score.PP = perfAttributes?.Total ?? 0.0;
|
||||
var perfAttributes = await performanceCalculator.CalculateAsync(parsedScore.ScoreInfo, difficultyAttributes, token).ConfigureAwait(false);
|
||||
score.PP = perfAttributes.Total;
|
||||
|
||||
var extendedScore = new ExtendedScore(score, livePp, perfAttributes);
|
||||
plays.Add(extendedScore);
|
||||
|
@ -382,17 +384,17 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
var player = players.First();
|
||||
|
||||
decimal totalLocalPP = 0;
|
||||
for (var i = 0; i < localOrdered.Count; i++)
|
||||
for (int i = 0; i < localOrdered.Count; i++)
|
||||
totalLocalPP += (decimal)(Math.Pow(0.95, i) * (localOrdered[i].SoloScore.PP ?? 0));
|
||||
|
||||
decimal totalLivePP = player.Statistics.PP ?? (decimal)0.0;
|
||||
|
||||
decimal nonBonusLivePP = 0;
|
||||
for (var i = 0; i < liveOrdered.Count; i++)
|
||||
for (int i = 0; i < liveOrdered.Count; i++)
|
||||
nonBonusLivePP += (decimal)(Math.Pow(0.95, i) * liveOrdered[i].LivePP ?? 0);
|
||||
|
||||
//todo: implement properly. this is pretty damn wrong.
|
||||
var playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
decimal playcountBonusPP = (totalLivePP - nonBonusLivePP);
|
||||
totalLocalPP += playcountBonusPP;
|
||||
|
||||
Schedule(() =>
|
||||
|
|
|
@ -1022,7 +1022,7 @@ namespace PerformanceCalculatorGUI.Screens
|
|||
{
|
||||
try
|
||||
{
|
||||
var scoreInfo = await apiManager.GetJsonFromApi<SoloScoreInfo>($"scores/{scoreId}");
|
||||
var scoreInfo = await apiManager.GetJsonFromApi<SoloScoreInfo>($"scores/{scoreId}").ConfigureAwait(false);
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
|
|
21
README.md
21
README.md
|
@ -13,7 +13,7 @@ This is part of a group of projects which are used in live deployments where the
|
|||
# Requirements
|
||||
|
||||
- A desktop platform with the [.NET 8.0 SDK](https://dotnet.microsoft.com/download) installed.
|
||||
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as the latest version of [Visual Studio](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
|
||||
- When working with the codebase, we recommend using an IDE with intelligent code completion and syntax highlighting, such as the latest version of [Visual Studio](https://visualstudio.microsoft.com/vs/), [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/) with the [EditorConfig](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) and [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit) plugin installed.
|
||||
- These instructions assume you have the the [CLI git client](https://git-scm.com/) installed, but any other GUI client such as GitKraken will suffice.
|
||||
|
||||
# Getting Started
|
||||
|
@ -32,8 +32,21 @@ Most relevant code is in the main [ppy/osu](https://github.com/ppy/osu) reposito
|
|||
git clone https://github.com/ppy/osu-tools
|
||||
git clone https://github.com/ppy/osu
|
||||
```
|
||||
- If you're planning to work on the difficulty and/or performance calculation changes you will need to use the `pp-dev` branch of the `osu` repository
|
||||
```shell
|
||||
cd osu
|
||||
git checkout -b pp-dev origin/pp-dev
|
||||
```
|
||||
- Run the `./UseLocalOsu.ps1` powershell script (or `./UseLocalOsu.sh`) to use your local copy of ppy/osu
|
||||
|
||||
### Code analysis
|
||||
|
||||
Before committing your code, please run a code formatter. This can be achieved by running `dotnet format` in the command line, or using the `Format code` command in your IDE.
|
||||
|
||||
We have adopted some cross-platform, compiler integrated analyzers. They can provide warnings when you are editing, building inside IDE or from command line, as-if they are provided by the compiler itself.
|
||||
|
||||
JetBrains ReSharper InspectCode is also used for wider rule sets. You can run it from PowerShell with `.\InspectCode.ps1`. Alternatively, you can install ReSharper or use Rider to get inline support in your IDE of choice.
|
||||
|
||||
## I want to run someone else's changes
|
||||
|
||||
- Clone all relevant repos into the same directory
|
||||
|
@ -53,11 +66,9 @@ git checkout -b branch_name smoogi/branch_name
|
|||
|
||||
# Contributing
|
||||
|
||||
When it comes to contributing to the project, the two main things you can do to help out are reporting issues and submitting pull requests.
|
||||
When it comes to contributing to the project, the two main things you can do to help out are reporting issues and submitting pull requests. You might want to refer to the [contributing guidelines](https://github.com/ppy/osu/blob/master/CONTRIBUTING.md) in the main osu! repository to understand how to help in the most effective way possible.
|
||||
|
||||
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured, with any libraries we are using, or with any processes involved with contributing, *please* bring it up. We welcome all feedback so we can make contributing to this project as painless as possible.
|
||||
|
||||
For those interested, we love to reward quality contributions via [bounties](https://docs.google.com/spreadsheets/d/1jNXfj_S3Pb5PErA-czDdC9DUu4IgUbe1Lt8E7CYUJuE/view?&rm=minimal#gid=523803337), paid out via PayPal or osu!supporter tags. Don't hesitate to [request a bounty](https://docs.google.com/forms/d/e/1FAIpQLSet_8iFAgPMG526pBZ2Kic6HSh7XPM3fE8xPcnWNkMzINDdYg/viewform) for your work on this project.
|
||||
We love to reward quality contributions. If you have made a large contribution, or are a regular contributor, you are welcome to [submit an expense via opencollective](https://opencollective.com/ppy/expenses/new). If you have any questions, feel free to [reach out to peppy](mailto:pe@ppy.sh) before doing so.
|
||||
|
||||
# Licence
|
||||
|
||||
|
|
|
@ -1,15 +1,35 @@
|
|||
<!-- Contains required properties for osu!tools projects. -->
|
||||
<!-- Contains required properties for osu!tools projects. -->
|
||||
<Project>
|
||||
<PropertyGroup Label="C#">
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Label="License">
|
||||
<None Include="..\osu-tools.licenseheader">
|
||||
<Link>osu-tools.licenseheader</Link>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Code Analysis">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" PrivateAssets="All" />
|
||||
<AdditionalFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\BannedSymbols.txt" />
|
||||
<!-- Rider compatibility: .globalconfig needs to be explicitly referenced instead of using the global file name. -->
|
||||
<GlobalAnalyzerConfigFiles Include="$(MSBuildThisFileDirectory)CodeAnalysis\osu.Tools.globalconfig" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Code Analysis">
|
||||
<AnalysisMode>Default</AnalysisMode>
|
||||
<AnalysisModeDesign>Default</AnalysisModeDesign>
|
||||
<AnalysisModeDocumentation>Recommended</AnalysisModeDocumentation>
|
||||
<AnalysisModeGlobalization>Recommended</AnalysisModeGlobalization>
|
||||
<AnalysisModeInteroperability>Recommended</AnalysisModeInteroperability>
|
||||
<AnalysisModeMaintainability>Recommended</AnalysisModeMaintainability>
|
||||
<AnalysisModeNaming>Default</AnalysisModeNaming>
|
||||
<AnalysisModePerformance>Minimum</AnalysisModePerformance>
|
||||
<AnalysisModeReliability>Recommended</AnalysisModeReliability>
|
||||
<AnalysisModeSecurity>Default</AnalysisModeSecurity>
|
||||
<AnalysisModeUsage>Default</AnalysisModeUsage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Project">
|
||||
<Company>ppy Pty Ltd</Company>
|
||||
<Copyright>Copyright (c) 2020 ppy Pty Ltd</Copyright>
|
||||
<RepositoryUrl>https://github.com/ppy/osu-tools</RepositoryUrl>
|
||||
<Copyright>Copyright (c) 2024 ppy Pty Ltd</Copyright>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
|
@ -7,6 +7,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceCalculator", "Pe
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerformanceCalculatorGUI", "PerformanceCalculatorGUI\PerformanceCalculatorGUI.csproj", "{BB34B7BA-CB01-4F5F-9532-B070F3A2C52E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{10DF8F12-50FD-45D8-8A38-17BA764BF54D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
osu.Tools.props = osu.Tools.props
|
||||
osu.Tools.sln.DotSettings = osu.Tools.sln.DotSettings
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeAnalysis", "CodeAnalysis", "{FB156649-D457-4D1A-969C-D3A23FD31513}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
CodeAnalysis\BannedSymbols.txt = CodeAnalysis\BannedSymbols.txt
|
||||
CodeAnalysis\osu.Tools.globalconfig = CodeAnalysis\osu.Tools.globalconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeLocalFunctionBody/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeMethodOrOperatorBody/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeModifiersOrder/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeNamespaceBody/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeEvident/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeRedundantParentheses/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeRedundantParentheses/@EntryIndexRemoved">True</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTrailingCommaInMultilineLists/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTypeMemberModifiers/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeTypeModifiers/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=AssignedValueIsNeverUsed/@EntryIndexedValue">HINT</s:String>
|
||||
|
@ -65,8 +67,9 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=CompareOfFloatsByEqualityOperator/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertClosureToMethodGroup/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertConditionalTernaryExpressionToSwitchExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertConstructorToMemberInitializers/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfDoToWhile/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToConditionalTernaryExpression/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToConditionalTernaryExpression/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToNullCoalescingAssignment/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToNullCoalescingExpression/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertIfStatementToSwitchExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
|
@ -80,6 +83,7 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToConstant_002ELocal/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToLambdaExpression/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToLocalFunction/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToPrimaryConstructor/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToStaticClass/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToUsingDeclaration/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertTypeCheckPatternToNullCheck/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
|
@ -149,7 +153,6 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PropertyCanBeMadeInitOnly_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PropertyCanBeMadeInitOnly_002ELocal/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=PublicConstructorInAbstractClass/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantAnonymousTypePropertyName/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArgumentDefaultValue/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantArrayCreationExpression/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantAttributeParentheses/@EntryIndexedValue">WARNING</s:String>
|
||||
|
@ -165,6 +168,7 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantImmediateDelegateInvocation/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantLambdaSignatureParentheses/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantReadonlyModifier/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantTypeDeclarationBody/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantTypeSpecificationInDefaultExpression/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantLinebreak/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=RedundantSpace/@EntryIndexedValue">WARNING</s:String>
|
||||
|
@ -251,6 +255,7 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UnusedType_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseAwaitUsing/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseCollectionCountProperty/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseCollectionExpression/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseConfigureAwaitFalseForAsyncDisposable/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseFormatSpecifierInFormatString/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseFormatSpecifierInInterpolation/@EntryIndexedValue">WARNING</s:String>
|
||||
|
@ -263,6 +268,7 @@
|
|||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseObjectOrCollectionInitializer/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UsePatternMatching/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseStringInterpolation/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=UseUtf8StringLiteral/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=VariableCanBeMadeConst/@EntryIndexedValue">WARNING</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=VirtualMemberCallInConstructor/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=VirtualMemberNeverOverridden_002EGlobal/@EntryIndexedValue">HINT</s:String>
|
||||
|
@ -335,12 +341,14 @@
|
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=API/@EntryIndexedValue">API</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ARGB/@EntryIndexedValue">ARGB</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BPM/@EntryIndexedValue">BPM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DDKK/@EntryIndexedValue">DDKK</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EF/@EntryIndexedValue">EF</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FPS/@EntryIndexedValue">FPS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GL/@EntryIndexedValue">GL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GLSL/@EntryIndexedValue">GLSL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HID/@EntryIndexedValue">HID</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HP/@EntryIndexedValue">HP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HSL/@EntryIndexedValue">HSL</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HSPA/@EntryIndexedValue">HSPA</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HSV/@EntryIndexedValue">HSV</s:String>
|
||||
|
@ -352,6 +360,8 @@
|
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IPC/@EntryIndexedValue">IPC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JIT/@EntryIndexedValue">JIT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KDDK/@EntryIndexedValue">KDDK</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KKDD/@EntryIndexedValue">KKDD</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LTRB/@EntryIndexedValue">LTRB</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MD/@EntryIndexedValue">MD5</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NS/@EntryIndexedValue">NS</s:String>
|
||||
|
@ -370,6 +380,7 @@
|
|||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=QAT/@EntryIndexedValue">QAT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=BNG/@EntryIndexedValue">BNG</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=WIP/@EntryIndexedValue">WIP</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpNaming/ApplyAutoDetectedRules/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">HINT</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue"><?xml version="1.0" encoding="utf-16"?>
|
||||
|
@ -834,6 +845,7 @@ See the LICENCE file in the repository root for full licence text.
|
|||
<s:Boolean x:Key="/Default/Environment/AutoImport2/=CSHARP/BlackLists/=System_002ENumerics_002E_002A/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/AutoImport2/=CSHARP/BlackLists/=System_002ESecurity_002ECryptography_002ERSA/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/AutoImport2/=CSHARP/BlackLists/=TagLib_002EMpeg4_002EBox/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/AutoImport2/=CSHARP/BlackLists/=Vortice_002E_002A/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECodeCleanup_002EFileHeader_002EFileHeaderSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EDaemon_002ESettings_002EMigration_002ESwaWarningsModeSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -841,6 +853,7 @@ See the LICENCE file in the repository root for full licence text.
|
|||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -1011,6 +1024,7 @@ private void load()
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Migratable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nightcore/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Omni/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=osump/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Overlined/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pausable/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pippidon/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -1047,4 +1061,6 @@ private void load()
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unplayed/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unproxy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unranked/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=velopack/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Welford_0027s/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Zoomable/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue