├── .config └── dotnet-tools.json ├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .idea └── .idea.osu.Tools │ └── .idea │ └── .name ├── .vscode ├── launch.json └── tasks.json ├── CodeAnalysis ├── BannedSymbols.txt └── osu.Tools.globalconfig ├── LICENCE ├── PerformanceCalculator ├── ApiCommand.cs ├── Difficulty │ ├── DifficultyCommand.cs │ ├── LegacyScoreAttributesCommand.cs │ ├── LegacyScoreConversionCommand.cs │ └── ModsCommand.cs ├── Leaderboard │ ├── LeaderboardCommand.cs │ └── LeaderboardPlayerInfo.cs ├── LegacyHelper.cs ├── Performance │ ├── LegacyScorePerformanceCommand.cs │ ├── PerformanceListingCommand.cs │ ├── ReplayPerformanceCommand.cs │ └── ScorePerformanceCommand.cs ├── PerformanceCalculator.csproj ├── ProcessorCommand.cs ├── ProcessorScoreDecoder.cs ├── ProcessorWorkingBeatmap.cs ├── Profile │ ├── ProfileCommand.cs │ └── UserPlayInfo.cs ├── Program.cs ├── README.md └── Simulate │ ├── CatchSimulateCommand.cs │ ├── ManiaSimulateCommand.cs │ ├── OsuSimulateCommand.cs │ ├── SimulateCommand.cs │ ├── SimulateListingCommand.cs │ └── TaikoSimulateCommand.cs ├── PerformanceCalculatorGUI ├── APIManager.cs ├── AttributeConversion.cs ├── Components │ ├── BeatmapCard.cs │ ├── ExtendedOsuCheckbox.cs │ ├── ExtendedOsuFileSelector.cs │ ├── ExtendedOsuSpriteText.cs │ ├── ExtendedProfileScore.cs │ ├── ExtendedUserModSelectOverlay.cs │ ├── LeaderboardTable.cs │ ├── Notification.cs │ ├── NotificationDisplay.cs │ ├── ProfileSortCriteria.cs │ ├── ScreenSelectionButton.cs │ ├── ScreenSelectionButtonIcon.cs │ ├── SettingsButton.cs │ ├── SettingsPopover.cs │ ├── StatefulButton.cs │ ├── StrainVisualizer.cs │ ├── TextBoxes │ │ ├── ExtendedLabelledTextBox.cs │ │ ├── FileChooserLabelledTextBox.cs │ │ ├── LabelledPasswordTextBox.cs │ │ ├── LimitedLabelledFractionalNumberBox.cs │ │ ├── LimitedLabelledNumberBox.cs │ │ └── ReadonlyOsuTextBox.cs │ ├── UserCard.cs │ └── VerboseLoadingLayer.cs ├── Configuration │ └── SettingsManager.cs ├── ExtendedCatchDifficultyCalculator.cs ├── ExtendedManiaDifficultyCalculator.cs ├── ExtendedOsuDifficultyCalculator.cs ├── ExtendedTaikoDifficultyCalculator.cs ├── HotReloadCallbackReceiver.cs ├── IExtendedDifficultyCalculator.cs ├── PerformanceCalculatorGUI.csproj ├── PerformanceCalculatorGame.cs ├── PerformanceCalculatorSceneManager.cs ├── ProcessorScoreDecoder.cs ├── ProcessorWorkingBeatmap.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── RulesetHelper.cs └── Screens │ ├── BeatmapLeaderboardScreen.cs │ ├── LeaderboardScreen.cs │ ├── ObjectInspection │ ├── CatchObjectInspectorRuleset.cs │ ├── ObjectDifficultyValuesContainer.cs │ ├── ObjectInspector.cs │ ├── ObjectInspectorDifficultyValue.cs │ ├── OsuObjectInspectorRuleset.cs │ ├── TaikoObjectInspectorRuleset.cs │ └── TimelineBlueprintContainer.cs │ ├── PerformanceCalculatorScreen.cs │ ├── ProfileScreen.cs │ ├── Simulate │ └── AttributesTable.cs │ └── SimulateScreen.cs ├── README.md ├── UseLocalOsu.ps1 ├── UseLocalOsu.sh ├── osu-tools.licenseheader ├── osu.Tools.props ├── osu.Tools.sln └── osu.Tools.sln.DotSettings /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "CodeFileSanity": { 6 | "version": "0.0.37", 7 | "commands": [ 8 | "CodeFileSanity" 9 | ] 10 | }, 11 | "jetbrains.resharper.globaltools": { 12 | "version": "2023.3.3", 13 | "commands": [ 14 | "jb" 15 | ] 16 | }, 17 | "nvika": { 18 | "version": "4.0.0", 19 | "commands": [ 20 | "nvika" 21 | ] 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Autodetect text files and ensure that we normalise their 2 | # line endings to lf internally. When checked out they may 3 | # use different line endings. 4 | * text=auto 5 | 6 | # Check out with crlf (Windows) line endings 7 | *.sln text eol=crlf 8 | *.csproj text eol=crlf 9 | *.cs text diff=csharp eol=crlf 10 | *.resx text eol=crlf 11 | *.vsixmanifest text eol=crlf 12 | packages.config text eol=crlf 13 | App.config text eol=crlf 14 | *.bat text eol=crlf 15 | *.cmd text eol=crlf 16 | *.snippet text eol=crlf 17 | *.manifest text eol=crlf 18 | *.licenseheader text eol=crlf 19 | 20 | # Check out with lf (UNIX) line endings 21 | *.sh text eol=lf 22 | .gitignore text eol=lf 23 | .gitattributes text eol=lf 24 | *.md text eol=lf 25 | .travis.yml text eol=lf -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | time: "17:00" 8 | open-pull-requests-limit: 0 # disabled until https://github.com/dependabot/dependabot-core/issues/369 is resolved. 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | inspect-code: 13 | name: Code Quality 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | 19 | - name: Install .NET 8.0.x 20 | uses: actions/setup-dotnet@v3 21 | with: 22 | dotnet-version: "8.0.x" 23 | 24 | - name: Restore Tools 25 | run: dotnet tool restore 26 | 27 | - name: Restore Packages 28 | run: dotnet restore 29 | 30 | - name: CodeFileSanity 31 | run: | 32 | # TODO: Add ignore filters and GitHub Workflow Command Reporting in CFS. That way we don't have to do this workaround. 33 | # FIXME: Suppress warnings from templates project 34 | exit_code=0 35 | while read -r line; do 36 | if [[ ! -z "$line" ]]; then 37 | echo "::error::$line" 38 | exit_code=1 39 | fi 40 | done <<< $(dotnet codefilesanity) 41 | exit $exit_code 42 | 43 | - name: InspectCode 44 | run: dotnet jb inspectcode $(pwd)/osu.Tools.sln --build --output="inspectcodereport.xml" --verbosity=WARN 45 | 46 | - name: NVika 47 | run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" --treatwarningsaserrors 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | [Ll]og/ 22 | 23 | # Visual Studio 2015 cache/options directory 24 | .vs/ 25 | # Uncomment if you have tasks that create the project's static files in wwwroot 26 | #wwwroot/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | project.fragment.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | *.VC.db 83 | *.VC.VC.opendb 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.pfx 191 | *.publishsettings 192 | node_modules/ 193 | orleans.codegen.cs 194 | Resource.designer.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # Python Tools for Visual Studio (PTVS) 251 | __pycache__/ 252 | *.pyc 253 | 254 | # Cake # 255 | /tools/** 256 | /build/tools/** 257 | /build/temp/** 258 | 259 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 260 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 261 | 262 | # User-specific stuff 263 | .idea/**/workspace.xml 264 | .idea/**/tasks.xml 265 | .idea/**/usage.statistics.xml 266 | .idea/**/dictionaries 267 | .idea/**/shelf 268 | .idea/*/.idea/projectSettingsUpdater.xml 269 | .idea/*/.idea/encodings.xml 270 | 271 | # Generated files 272 | .idea/**/contentModel.xml 273 | 274 | # Sensitive or high-churn files 275 | .idea/**/dataSources/ 276 | .idea/**/dataSources.ids 277 | .idea/**/dataSources.local.xml 278 | .idea/**/sqlDataSources.xml 279 | .idea/**/dynamic.xml 280 | .idea/**/uiDesigner.xml 281 | .idea/**/dbnavigator.xml 282 | 283 | # Gradle 284 | .idea/**/gradle.xml 285 | .idea/**/libraries 286 | 287 | # Gradle and Maven with auto-import 288 | # When using Gradle or Maven with auto-import, you should exclude module files, 289 | # since they will be recreated, and may cause churn. Uncomment if using 290 | # auto-import. 291 | .idea/modules.xml 292 | .idea/*.iml 293 | .idea/modules 294 | *.iml 295 | *.ipr 296 | 297 | # CMake 298 | cmake-build-*/ 299 | 300 | # Mongo Explorer plugin 301 | .idea/**/mongoSettings.xml 302 | 303 | # File-based project format 304 | *.iws 305 | 306 | # IntelliJ 307 | out/ 308 | 309 | # mpeltonen/sbt-idea plugin 310 | .idea_modules/ 311 | 312 | # JIRA plugin 313 | atlassian-ide-plugin.xml 314 | 315 | # Cursive Clojure plugin 316 | .idea/replstate.xml 317 | 318 | # Crashlytics plugin (for Android Studio and IntelliJ) 319 | com_crashlytics_export_strings.xml 320 | crashlytics.properties 321 | crashlytics-build.properties 322 | fabric.properties 323 | 324 | # Editor-based Rest Client 325 | .idea/httpRequests 326 | 327 | # Android studio 3.1+ serialized cache file 328 | .idea/caches/build_file_checksums.ser 329 | 330 | # fastlane 331 | fastlane/report.xml 332 | 333 | # inspectcode 334 | inspectcodereport.xml 335 | inspectcode 336 | 337 | # BenchmarkDotNet 338 | /BenchmarkDotNet.Artifacts 339 | 340 | *.GeneratedMSBuildEditorConfig.editorconfig 341 | 342 | # Fody (pulled in by Realm) - schema file 343 | FodyWeavers.xsd 344 | 345 | .idea/.idea.osu.Desktop/.idea/misc.xml 346 | .idea/.idea.osu.Android/.idea/deploymentTargetDropDown.xml 347 | 348 | PerformanceCalculator/cache/ 349 | -------------------------------------------------------------------------------- /.idea/.idea.osu.Tools/.idea/.name: -------------------------------------------------------------------------------- 1 | osu.Tools -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug (Performance Calculator)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "program": "dotnet", 9 | "args": [ 10 | "${workspaceRoot}/PerformanceCalculator/bin/Debug/net8.0/PerformanceCalculator.dll", 11 | "place-your-arguments-here (launch.json)" 12 | ], 13 | "cwd": "${workspaceRoot}", 14 | "preLaunchTask": "Build (Debug)", 15 | "env": {}, 16 | "console": "internalConsole" 17 | }, 18 | { 19 | "name": "Release (Performance Calculator)", 20 | "type": "coreclr", 21 | "request": "launch", 22 | "program": "dotnet", 23 | "args": [ 24 | "${workspaceRoot}/PerformanceCalculator/bin/Release/net8.0/PerformanceCalculator.dll", 25 | "place-your-arguments-here (launch.json)" 26 | ], 27 | "cwd": "${workspaceRoot}", 28 | "preLaunchTask": "Build (Release)", 29 | "env": {}, 30 | "console": "internalConsole" 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Build (Debug)", 8 | "type": "shell", 9 | "command": "dotnet", 10 | "args": [ 11 | "build", 12 | "--no-restore", 13 | "/p:GenerateFullPaths=true", 14 | "/m", 15 | "/verbosity:m" 16 | ], 17 | "group": "build", 18 | "problemMatcher": "$msCompile" 19 | }, 20 | { 21 | "label": "Build (Release)", 22 | "type": "shell", 23 | "command": "dotnet", 24 | "args": [ 25 | "build", 26 | "--no-restore", 27 | "/p:Configuration=Release", 28 | "/p:GenerateFullPaths=true", 29 | "/m", 30 | "/verbosity:m" 31 | ], 32 | "group": "build", 33 | "problemMatcher": "$msCompile" 34 | }, 35 | { 36 | "label": "Restore", 37 | "type": "shell", 38 | "command": "dotnet", 39 | "args": [ 40 | "restore" 41 | ], 42 | "problemMatcher": [] 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /CodeAnalysis/BannedSymbols.txt: -------------------------------------------------------------------------------- 1 | M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable or EqualityComparer.Default instead. 2 | M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable or EqualityComparer.Default instead. 3 | M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable or EqualityComparer.Default instead. 4 | M:System.Nullable`1.Equals(System.Object)~System.Boolean;Use == instead. 5 | T:System.IComparable;Don't use non-generic IComparable. Use generic version instead. 6 | T:SixLabors.ImageSharp.IDeepCloneable`1;Use osu.Game.Utils.IDeepCloneable instead. 7 | M:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText. 8 | M:osu.Framework.Bindables.IBindableList`1.GetBoundCopy();Fails on iOS. Use manual ctor + BindTo instead. (see https://github.com/mono/mono/issues/19900) 9 | T:NuGet.Packaging.CollectionExtensions;Don't use internal extension methods. 10 | M:Realms.IRealmCollection`1.SubscribeForNotifications`1(Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IRealmCollection,NotificationCallbackDelegate) instead. 11 | M:System.Guid.#ctor;Probably meaning to use Guid.NewGuid() instead. If actually wanting empty, use Guid.Empty. 12 | M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Linq.IQueryable{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IQueryable,NotificationCallbackDelegate) instead. 13 | M:Realms.CollectionExtensions.SubscribeForNotifications`1(System.Collections.Generic.IList{``0},Realms.NotificationCallbackDelegate{``0});Use osu.Game.Database.RealmObjectExtensions.QueryAsyncWithNotifications(IList,NotificationCallbackDelegate) instead. 14 | M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks. 15 | P:System.Threading.Tasks.Task`1.Result;Don't use Task.Result. Use Task.GetResultSafely() to ensure we avoid deadlocks. 16 | M:System.Threading.ManualResetEventSlim.Wait();Specify a timeout to avoid waiting forever. 17 | M:Humanizer.InflectorExtensions.Pascalize(System.String);Humanizer's .Pascalize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToPascalCase() instead. 18 | M:Humanizer.InflectorExtensions.Camelize(System.String);Humanizer's .Camelize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToCamelCase() instead. 19 | M:Humanizer.InflectorExtensions.Underscore(System.String);Humanizer's .Underscore() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToSnakeCase() instead. 20 | M:Humanizer.InflectorExtensions.Kebaberize(System.String);Humanizer's .Kebaberize() extension method changes behaviour depending on CultureInfo.CurrentCulture. Use StringDehumanizeExtensions.ToKebabCase() instead. 21 | -------------------------------------------------------------------------------- /CodeAnalysis/osu.Tools.globalconfig: -------------------------------------------------------------------------------- 1 | # .NET Code Style 2 | # IDE styles reference: https://docs.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ 3 | is_global = true 4 | 5 | # IDE0001: Simplify names 6 | dotnet_diagnostic.IDE0001.severity = warning 7 | 8 | # IDE0002: Simplify member access 9 | dotnet_diagnostic.IDE0002.severity = warning 10 | 11 | # IDE0003: Remove qualification 12 | dotnet_diagnostic.IDE0003.severity = warning 13 | 14 | # IDE0004: Remove unnecessary cast 15 | dotnet_diagnostic.IDE0004.severity = warning 16 | 17 | # IDE0005: Remove unnecessary imports 18 | dotnet_diagnostic.IDE0005.severity = warning 19 | 20 | # IDE0034: Simplify default literal 21 | dotnet_diagnostic.IDE0034.severity = warning 22 | 23 | # IDE0036: Sort modifiers 24 | dotnet_diagnostic.IDE0036.severity = warning 25 | 26 | # IDE0040: Add accessibility modifier 27 | dotnet_diagnostic.IDE0040.severity = warning 28 | 29 | # IDE0049: Use keyword for type name 30 | dotnet_diagnostic.IDE0040.severity = warning 31 | 32 | # IDE0055: Fix formatting 33 | dotnet_diagnostic.IDE0055.severity = warning 34 | 35 | # IDE0051: Private method is unused 36 | dotnet_diagnostic.IDE0051.severity = silent 37 | 38 | # IDE0052: Private member is unused 39 | dotnet_diagnostic.IDE0052.severity = silent 40 | 41 | # IDE0073: File header 42 | dotnet_diagnostic.IDE0073.severity = warning 43 | 44 | # IDE0130: Namespace mismatch with folder 45 | dotnet_diagnostic.IDE0130.severity = warning 46 | 47 | # IDE1006: Naming style 48 | dotnet_diagnostic.IDE1006.severity = warning 49 | 50 | # CA1305: Specify IFormatProvider 51 | # Too many noisy warnings for parsing/formatting numbers 52 | dotnet_diagnostic.CA1305.severity = none 53 | 54 | # CA1507: Use nameof to express symbol names 55 | # Flaggs serialization name attributes 56 | dotnet_diagnostic.CA1507.severity = suggestion 57 | 58 | # CA1806: Do not ignore method results 59 | # The usages for numeric parsing are explicitly optional 60 | dotnet_diagnostic.CA1806.severity = suggestion 61 | 62 | # CA1822: Mark members as static 63 | # Potential false positive around reflection/too much noise 64 | dotnet_diagnostic.CA1822.severity = none 65 | 66 | # CA1826: Do not use Enumerable method on indexable collections 67 | dotnet_diagnostic.CA1826.severity = suggestion 68 | 69 | # CA1859: Use concrete types when possible for improved performance 70 | # Involves design considerations 71 | dotnet_diagnostic.CA1859.severity = suggestion 72 | 73 | # CA1860: Avoid using 'Enumerable.Any()' extension method 74 | dotnet_diagnostic.CA1860.severity = suggestion 75 | 76 | # CA1861: Avoid constant arrays as arguments 77 | # Outdated with collection expressions 78 | dotnet_diagnostic.CA1861.severity = suggestion 79 | 80 | # CA2007: Consider calling ConfigureAwait on the awaited task 81 | dotnet_diagnostic.CA2007.severity = warning 82 | 83 | # CA2016: Forward the 'CancellationToken' parameter to methods 84 | # Some overloads are having special handling for debugger 85 | dotnet_diagnostic.CA2016.severity = suggestion 86 | 87 | # CA2021: Do not call Enumerable.Cast or Enumerable.OfType with incompatible types 88 | # Causing a lot of false positives with generics 89 | dotnet_diagnostic.CA2021.severity = none 90 | 91 | # CA2101: Specify marshaling for P/Invoke string arguments 92 | # Reports warning for all non-UTF16 usages on DllImport; consider migrating to LibraryImport 93 | dotnet_diagnostic.CA2101.severity = none 94 | 95 | # CA2201: Do not raise reserved exception types 96 | dotnet_diagnostic.CA2201.severity = warning 97 | 98 | # CA2208: Instantiate argument exceptions correctly 99 | dotnet_diagnostic.CA2208.severity = suggestion 100 | 101 | # CA2242: Test for NaN correctly 102 | dotnet_diagnostic.CA2242.severity = warning 103 | 104 | # Banned APIs 105 | dotnet_diagnostic.RS0030.severity = error 106 | 107 | # Temporarily disable analysing CanBeNull = true in NRT contexts due to mobile issues. 108 | # See: https://github.com/ppy/osu/pull/19677 109 | dotnet_diagnostic.OSUF001.severity = none 110 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 ppy Pty Ltd . 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /PerformanceCalculator/ApiCommand.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System.Collections.Generic; 5 | using System.ComponentModel.DataAnnotations; 6 | using System.Globalization; 7 | using System.Net.Http; 8 | using JetBrains.Annotations; 9 | using McMaster.Extensions.CommandLineUtils; 10 | using osu.Framework.IO.Network; 11 | 12 | namespace PerformanceCalculator 13 | { 14 | public abstract class ApiCommand : ProcessorCommand 15 | { 16 | [UsedImplicitly] 17 | [Required] 18 | [Argument(98, Name = "client id", Description = "API Client ID, which you can get from here: https://osu.ppy.sh/home/account/edit#new-oauth-application")] 19 | public string ClientId { get; } 20 | 21 | [UsedImplicitly] 22 | [Required] 23 | [Argument(99, Name = "client secret", Description = "API Client Secret, which you can get from here: https://osu.ppy.sh/home/account/edit#new-oauth-application")] 24 | public string ClientSecret { get; } 25 | 26 | private string apiAccessToken; 27 | 28 | // WARN: keep in sync with /osu.Game/Online/API/APIAccess.cs APIVersion 29 | private const int api_version = 20220705; 30 | 31 | public override void OnExecute(CommandLineApplication app, IConsole console) 32 | { 33 | getAccessToken(); 34 | base.OnExecute(app, console); 35 | } 36 | 37 | protected T GetJsonFromApi(string request, HttpMethod method = null, Dictionary parameters = null) 38 | { 39 | using var req = new JsonWebRequest($"{Program.ENDPOINT_CONFIGURATION.APIUrl}/api/v2/{request}"); 40 | req.Method = method ?? HttpMethod.Get; 41 | req.AddHeader("x-api-version", api_version.ToString(CultureInfo.InvariantCulture)); 42 | req.AddHeader(System.Net.HttpRequestHeader.Authorization.ToString(), $"Bearer {apiAccessToken}"); 43 | 44 | if (parameters != null) 45 | { 46 | foreach ((string key, string value) in parameters) 47 | req.AddParameter(key, value); 48 | } 49 | 50 | req.Perform(); 51 | 52 | return req.ResponseObject; 53 | } 54 | 55 | private void getAccessToken() 56 | { 57 | using var req = new JsonWebRequest($"{Program.ENDPOINT_CONFIGURATION.APIUrl}/oauth/token") 58 | { 59 | Method = HttpMethod.Post 60 | }; 61 | 62 | req.AddParameter("client_id", ClientId); 63 | req.AddParameter("client_secret", ClientSecret); 64 | req.AddParameter("grant_type", "client_credentials"); 65 | req.AddParameter("scope", "public"); 66 | req.Perform(); 67 | 68 | apiAccessToken = req.ResponseObject.access_token.ToString(); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PerformanceCalculator/Difficulty/DifficultyCommand.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. 2 | // See the LICENCE file in the repository root for full licence text. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.IO; 7 | using System.Linq; 8 | using Alba.CsConsoleFormat; 9 | using Humanizer; 10 | using JetBrains.Annotations; 11 | using McMaster.Extensions.CommandLineUtils; 12 | using Newtonsoft.Json; 13 | using osu.Game.Beatmaps; 14 | using osu.Game.Online.API; 15 | using osu.Game.Rulesets.Difficulty; 16 | 17 | namespace PerformanceCalculator.Difficulty 18 | { 19 | [Command(Name = "difficulty", Description = "Computes the difficulty of a beatmap.")] 20 | public class DifficultyCommand : ProcessorCommand 21 | { 22 | [UsedImplicitly] 23 | [Argument(0, Name = "path", Description = "Required. A beatmap file (.osu), beatmap ID, or a folder containing .osu files to compute the difficulty for.")] 24 | public string Path { get; } 25 | 26 | [UsedImplicitly] 27 | [Option(CommandOptionType.SingleOrNoValue, Template = "-r|--ruleset:", Description = "Optional. The ruleset to compute the beatmap difficulty for, if it's a convertible beatmap.\n" 28 | + "Values: 0 - osu!, 1 - osu!taiko, 2 - osu!catch, 3 - osu!mania")] 29 | [AllowedValues("0", "1", "2", "3")] 30 | public int? Ruleset { get; } 31 | 32 | [UsedImplicitly] 33 | [Option(CommandOptionType.MultipleValue, Template = "-m|--m ", Description = "One for each mod. The mods to compute the difficulty with." 34 | + "Values: hr, dt, hd, fl, ez, 4k, 5k, etc...")] 35 | public string[] Mods { get; } 36 | 37 | [UsedImplicitly] 38 | [Option(CommandOptionType.MultipleValue, Template = "-o|--mod-option