97 Commits

Author SHA1 Message Date
17d56f8db0 now completely in sync with master 2025-12-16 20:22:38 +03:00
9637ea1df7 again**2 2025-12-16 19:51:36 +03:00
0940d61f7e try again 2025-12-16 19:47:28 +03:00
e6a6352a9c sync with master fully 2025-12-16 19:39:40 +03:00
86f0159e65 adjust some CI settings 2025-12-15 20:32:33 +03:00
ae5a64ba81 fix most failing test cases 2025-12-15 20:29:31 +03:00
e3a7ae30cd prevent an exception if icon is broken (probably) 2025-12-13 22:41:23 +03:00
b6f845d99c slightly change score panels and mod icons 2025-12-13 02:41:05 +03:00
a1d6bda63e hide online status if no map is actually selected (ssv1/v2) 2025-12-12 00:06:05 +03:00
547d22a4b5 update some URLs to match instance, fix potential mp crash 2025-12-11 23:57:01 +03:00
b4c530ac04 add a very safe check for IApplicableFailExit mods 2025-12-09 23:59:35 +03:00
5af05d2479 show a message if we successfully migrate db to new place 2025-12-09 23:52:57 +03:00
43ab18ffea hide quit+replay button in most cases where replay can't be saved 2025-12-09 23:15:25 +03:00
9f59259a40 update volume meter design a bit more 2025-12-09 22:45:15 +03:00
82b3015fcc and again? 2025-12-09 21:35:24 +03:00
68f92ab57c messed things up again 2025-12-09 20:24:09 +03:00
d76d4d9a35 okay, i messed things up 2025-12-09 20:20:07 +03:00
Bartłomiej Dach
bb7417c099 Filter out more exceptions from being sent to sentry
More or less covers the first page of client sentry issues sorted by
volume, all of which is pretty much useless for anything because it's
client-specific-failure noise.
2025-12-09 20:19:16 +03:00
Dan Balasescu
066e093987 Adjust vote-to-skip to be explicit about states 2025-12-09 20:19:16 +03:00
Dan Balasescu
56e0c3e65d Fix potentially unsafe quick play event handling 2025-12-09 20:19:16 +03:00
Natelytle
89d7726903 Rank swap mod 2025-12-09 20:19:16 +03:00
Dan Balasescu
36f1bfef07 Fix incorrect quick play download progress 2025-12-09 20:19:15 +03:00
Dan Balasescu
118f07878a Allow score panel to animate 2025-12-09 20:19:15 +03:00
Dan Balasescu
e144968893 Remove quick play round results scroll animation 2025-12-09 20:19:15 +03:00
Dan Balasescu
d2ffea41c6 Consider abandon time for user placements 2025-12-09 20:19:15 +03:00
Dan Balasescu
a8be9b1381 Make quick play chat retain focus after posting 2025-12-09 20:19:15 +03:00
490a6fd724 fix out of range exception in changelog overlay 2025-12-08 17:34:27 +03:00
237e1828f8 add option for playing miss sound on any combo break, make...
exit & restart game options in fail condition mods mutually exclusive
2025-12-07 13:14:38 +03:00
3413f722f7 make volume meter use argon counter (it looks cool) 2025-12-06 23:52:20 +03:00
9f779dac03 forgot to disable christmas intro after testing 2025-12-06 21:57:44 +03:00
0727c53cdc bump to 2025.12.05-lazer 2025-12-06 21:52:53 +03:00
a57ff24191 bump to 2025.1203.0-tachyon, add no intro option, slightly change seasonal bg code 2025-12-06 21:51:48 +03:00
bdb3418b67 fix useless DB versioning in release builds
Idk why, but in my first commit here I just commented out the lines
restricting DB schema suffixes to debug builds only, and before all that
mess there was a "TODO: fix".
I'm only doing this for sake of tools like BeatmapExporter and to not
clog up disk space when newer schema versions arrive.
This should work well with existing installations (hopefully)
2025-12-02 20:15:00 +03:00
936640edeb update some configs for iOS 2025-11-21 19:04:31 +03:00
1187d03333 prepare repo for github ci/cd (mostly) 2025-11-21 18:59:41 +03:00
3bd996ee43 synchronize with github (tag 2025.1119.0-tachyon) 2025-11-19 15:13:25 +03:00
37b9f91d42 make discord rich presence work 2025-11-19 14:03:57 +03:00
1a5a5606dc don't log that we're running an unofficial build 2025-11-19 12:02:27 +03:00
87ff1051e9 set up sentry (glitchtip) logging properly 2025-11-18 23:27:57 +03:00
2e4b0ff197 make score cards for failed scores look better 2025-11-18 15:33:37 +03:00
499f410c94 slightly changed warnings for old windows versions 2025-11-18 14:44:34 +03:00
616c0d8ecd make key counters show proper readable key names 2025-11-18 14:24:05 +03:00
ed889138a0 break countdown now uses argon-style counter 2025-11-18 13:23:44 +03:00
18075bef29 display score retractions in recent activity 2025-11-17 21:28:03 +03:00
bc7780a870 updated the first players cutoff date for user profiles 2025-11-17 20:55:42 +03:00
8930b8fadb synchronize with github (tag 2025.1105.0) 2025-11-17 20:41:55 +03:00
2d457f4305 use online status of beatmap instead of mapset 2025-11-17 20:14:23 +03:00
a784734f94 fix up a couple strings 2025-11-17 20:10:54 +03:00
ecfd4764e7 fixed a blunder 2025-11-16 22:29:25 +03:00
f5ca5083d6 implement pp for legacy song select 2025-11-16 21:21:12 +03:00
1d7c77d8d6 add performance points to selectv2 beatmap info wedge 2025-11-16 20:49:27 +03:00
774e52fbd6 slight result screen score panel redesign 2025-11-16 18:52:04 +03:00
a9d7a9d5d5 score panel is now tinted, plus some other changes 2025-11-16 02:48:41 +03:00
f7069b1009 minor fixes for some mods 2025-11-16 02:47:38 +03:00
c3ce5dc787 add argon-style longest combo counter 2025-11-15 19:24:49 +03:00
98076e2092 add skinnable online status and star rating components 2025-11-15 19:03:14 +03:00
b7d1092f90 Merge branch 'master' of https://gitea.jvnko.boats/jvnkosu/client 2025-11-15 17:02:04 +03:00
08db90c278 some minor hud changes
- argon-style cps counter
- keybinds in key counters (for now, only default)
2025-11-15 16:45:14 +03:00
b7e36164c3 update issue templates 2025-11-14 22:22:43 +01:00
0f5f13858d exit game option for fail condition mods (SD, PF, AC) 2025-11-13 21:41:09 +03:00
89a0c75156 all user-playable mods are now always ranked 2025-11-12 20:53:07 +03:00
ab7e5c94f1 make autoupdates work, at last 2025-11-11 19:11:36 +03:00
8dc9ea4553 add startup disclaimer 2025-11-11 18:14:38 +03:00
dcf553c252 Revert "Remove disclaimer screen completely"
This reverts commit bd0e2b4dde.
2025-11-11 16:45:04 +03:00
43f3a506ea new icon + default logo color 2025-11-11 00:04:18 +03:00
ab51579c27 added quit w/ replay button to pause menu; minor visual changes for ranks 2025-11-10 22:39:10 +03:00
d8e977c05f minor changes to mod scoring, all mods are ranked now
Probably all user-playable mods are ranked by default now,
Mania key mods were reverted to 1.0x score multiplier
2025-11-10 18:52:07 +03:00
c023767df9 bump to 2025.1031.0-tachyon + misc changes for debug builds 2025-11-08 16:26:06 +03:00
d47e26f1ae now reproducible! 2025-09-12 23:44:01 +03:00
b0e5ae1109 some minor very UI changes 2025-09-12 22:39:07 +03:00
47b859ab17 l10n: replace "osu!" with "game" where suitable 2025-09-12 21:59:58 +03:00
5e523eb0b1 bump to 2025.912.0 2025-09-12 18:10:03 +03:00
Dean Herbert
d912f8c3b9 Lazer release 2025-09
For tagging purposes.
2025-09-12 16:30:29 +09:00
65f275106e update license information in various places (and readme) 2025-08-31 22:47:36 +03:00
6e374762fd synchronize with github 2025-08-31 21:26:21 +03:00
80646a166c add settings toggle to not delete imported archives 2025-08-31 19:39:13 +03:00
8f0510d903 made beatmap anonymization code a bit less awful 2025-08-31 15:06:24 +03:00
02e7000ee4 update editor beatmap anonymization code to update not just first diff 2025-08-30 22:56:01 +03:00
081355864e add beatmap editor option to remove online data of a map 2025-08-29 20:19:39 +03:00
6435a835d1 fix background category selection (this time for real) 2025-08-29 18:48:13 +03:00
628181a883 also update colour on load 2025-08-27 01:11:57 +03:00
835329efd3 synchronize with github 2025-08-27 00:59:45 +03:00
5399943118 update logo colour only when changing setting value 2025-08-27 00:58:26 +03:00
d07f82f6f4 refactor custom seasonal background code
some of it may be trauma-inducing, but I don't know how to make it
better
2025-08-27 00:43:26 +03:00
5b186bb740 potentially make logo look less weird (untested)
uh, yeah, I accidentally flipped the colors around in the UpdateColour() method (which I should've probably make private or protected), and it's the reason why the logo overall looked dimmer than it should've

anyhow, this should *probably* look a bit better, don't have any means to test it yet though
2025-08-25 12:46:27 +02:00
6cb99c13c2 added cookie color customization (which shouldn't have been done) 2025-08-24 19:46:36 +03:00
96008e06ab added settings toggle for song select v1 2025-08-24 05:42:59 +03:00
590b0a8028 welcome back select v1 2025-08-24 04:55:25 +03:00
e78c8fa03d (NOT STABLE!!) Added custom mode using music from MainMenu 2025-08-23 22:54:22 +03:00
70f7f09a83 synchronize with github (ppy/osu) 2025-08-23 18:11:07 +03:00
490137405f added installer build script, adapted autoupdates (not functional yet) 2025-08-22 22:26:17 +03:00
f3c6f53f70 added version to 'experimental version' banner 2025-08-22 20:19:18 +03:00
8cb5c682b4 make seasonal bg config strings localisable 2025-08-22 19:07:15 +03:00
c3d79295d3 made seasonal background notifications transient 2025-08-22 16:07:28 +03:00
f31d310135 small fixes (vibe-sleeping) 2025-08-22 04:17:25 +03:00
26029de27d Added customs wallpaper in a menu. 2025-08-22 03:10:55 +03:00
c37f72f567 jvnkosu initial bringup
Some checks failed
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Test (map[fullname:ubuntu-latest prettyname:Linux], MultiThreaded) (push) Has been cancelled
Continuous Integration / Test (map[fullname:ubuntu-latest prettyname:Linux], SingleThread) (push) Has been cancelled
Continuous Integration / Test (map[fullname:windows-latest prettyname:Windows], MultiThreaded) (push) Has been cancelled
Continuous Integration / Test (map[fullname:windows-latest prettyname:Windows], SingleThread) (push) Has been cancelled
Continuous Integration / Build only (Android) (push) Has been cancelled
Continuous Integration / Build only (iOS) (push) Has been cancelled
2025-08-21 22:12:07 +03:00
242 changed files with 2794 additions and 1215 deletions

View File

@@ -21,7 +21,7 @@
]
},
"ppy.localisationanalyser.tools": {
"version": "2025.1208.0",
"version": "2024.802.0",
"commands": [
"localisation"
]

View File

@@ -1,12 +1,6 @@
blank_issues_enabled: false
blank_issues_enabled: true
contact_links:
- name: Help
url: https://github.com/ppy/osu/discussions/categories/q-a
about: osu! not working or performing as you'd expect? Not sure it's a bug? Check the Q&A section!
- name: Suggestions or feature request
url: https://github.com/ppy/osu/discussions/categories/ideas
about: Got something you think should change or be added? Search for or start a new discussion!
- name: osu!stable issues
url: https://github.com/ppy/osu-stable-issues
about: For osu!(stable) - ie. the current "live" game version, check out the dedicated repository. Note that this is for serious bug reports only, not tech support.
url: https://t.me/jvnkosu_chat
about: Your jvnkosu! is not working right? Please contact us using our Telegram chat

View File

@@ -1,8 +1,10 @@
name: Update osu-web mod definitions
name: Update osu-web mod definitions (DO NOT USE YET!!!!!)
on:
push:
tags:
- '*'
workflow_dispatch:
# push:
# tags:
# - '*'
permissions:
contents: read # to fetch code (actions/checkout)

View File

@@ -1,4 +1,10 @@
on: [push, pull_request]
on:
push:
tags:
- '*'
workflow_dispatch:
name: Continuous Integration
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -33,7 +39,7 @@ jobs:
key: inspectcode-${{ hashFiles('.config/dotnet-tools.json', '.github/workflows/ci.yml', 'osu.sln*', 'osu*.slnf', '.editorconfig', '.globalconfig', 'CodeAnalysis/*', '**/*.csproj', '**/*.props') }}
- name: Dotnet code style
run: dotnet build -c Debug -warnaserror osu.Desktop.slnf -p:EnforceCodeStyleInBuild=true
run: dotnet build -c Debug -warnaserror osu.Desktop.slnf
- name: CodeFileSanity
run: |

View File

@@ -4,6 +4,7 @@ on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
notify_pending_production_deploy:
@@ -12,7 +13,7 @@ jobs:
- name: Submit pending deployment notification
run: |
export TITLE="Pending osu Production Deployment: $GITHUB_REF_NAME"
export URL="https://github.com/ppy/osu/actions/runs/$GITHUB_RUN_ID"
export URL="https://github.com/jvnkosu-dev/client/actions/runs/$GITHUB_RUN_ID"
export DESCRIPTION="Awaiting approval for building NuGet packages for tag $GITHUB_REF_NAME:
[View Workflow Run]($URL)"
export ACTOR_ICON="https://avatars.githubusercontent.com/u/$GITHUB_ACTOR_ID"

View File

@@ -21,9 +21,9 @@ jobs:
uses: getsentry/action-release@v1
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ppy
SENTRY_PROJECT: osu
SENTRY_URL: https://sentry.ppy.sh/
SENTRY_ORG: jvnkosu
SENTRY_PROJECT: client
SENTRY_URL: https://satellite.jvnko.boats/
with:
environment: production
version: osu@${{ github.ref_name }}
version: jvnkosu@${{ github.ref_name }}

3
.gitignore vendored
View File

@@ -19,6 +19,7 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Pp]ub/
# Visual Studio 2015 cache/options directory
.vs/
@@ -343,4 +344,4 @@ inspectcode
FodyWeavers.xsd
.idea/.idea.osu.Desktop/.idea/misc.xml
.idea/.idea.osu.Android/.idea/deploymentTargetDropDown.xml
.idea/.idea.osu.Android/.idea/deploymentTargetDropDown.xml

36
.vscode/launch.json vendored
View File

@@ -7,9 +7,9 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/net8.0/osu!.dll"
"${workspaceFolder}/osu.Desktop/bin/Debug/net8.0/osu!.dll"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build osu! (Debug)",
"console": "internalConsole"
},
@@ -19,9 +19,9 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/net8.0/osu!.dll"
"${workspaceFolder}/osu.Desktop/bin/Release/net8.0/osu!.dll"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build osu! (Release)",
"console": "internalConsole"
},
@@ -31,9 +31,9 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Debug/net8.0/osu.Game.Tests.dll"
"${workspaceFolder}/osu.Game.Tests/bin/Debug/net8.0/osu.Game.Tests.dll"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build tests (Debug)",
"console": "internalConsole"
},
@@ -43,9 +43,9 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tests/bin/Release/net8.0/osu.Game.Tests.dll"
"${workspaceFolder}/osu.Game.Tests/bin/Release/net8.0/osu.Game.Tests.dll"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build tests (Release)",
"console": "internalConsole"
},
@@ -55,10 +55,10 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Debug/net8.0/osu!.dll",
"${workspaceFolder}/osu.Desktop/bin/Debug/net8.0/osu!.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build osu! (Debug)",
"console": "internalConsole"
},
@@ -68,10 +68,10 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Desktop/bin/Release/net8.0/osu!.dll",
"${workspaceFolder}/osu.Desktop/bin/Release/net8.0/osu!.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build osu! (Release)",
"console": "internalConsole"
},
@@ -81,10 +81,10 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll",
"${workspaceFolder}/osu.Game.Tournament.Tests/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build tournament tests (Debug)",
"console": "internalConsole"
},
@@ -94,10 +94,10 @@
"request": "launch",
"program": "dotnet",
"args": [
"${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll",
"${workspaceFolder}/osu.Game.Tournament.Tests/bin/Debug/net8.0/osu.Game.Tournament.Tests.dll",
"--tournament"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build tournament tests (Release)",
"console": "internalConsole"
},
@@ -105,12 +105,12 @@
"name": "Benchmark",
"type": "coreclr",
"request": "launch",
"program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/net8.0/osu.Game.Benchmarks.dll",
"program": "${workspaceFolder}/osu.Game.Benchmarks/bin/Release/net8.0/osu.Game.Benchmarks.dll",
"args": [
"--filter",
"*"
],
"cwd": "${workspaceRoot}",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build benchmarks",
"console": "internalConsole"
}

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "osu.Desktop.slnf"
}

View File

@@ -49,7 +49,7 @@
<PackageProjectUrl>https://github.com/ppy/osu</PackageProjectUrl>
<RepositoryUrl>https://github.com/ppy/osu</RepositoryUrl>
<PackageReleaseNotes>Automated release.</PackageReleaseNotes>
<Company>ppy Pty Ltd</Company>
<Company>ppy Pty Ltd, jvnkosu! team</Company>
<Copyright>Copyright (c) 2025 ppy Pty Ltd</Copyright>
<PackageTags>osu game</PackageTags>
</PropertyGroup>

19
MakeInstaller.ps1 Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env powershell
param (
[string]$Version,
[string]$BuildConfig = "Release"
)
if ($Version -eq "") {
Write-Host "Usage: .\MakeInstaller.ps1 <VERSION_NUMBER> [-BuildConfig <BUILD_CONFIG>]"
Write-Host "Example: .\MakeInstaller.ps1 2025.823.0 -BuildConfig Debug"
exit
}
$tmpPub = ".\pub"
if (-not (Test-Path -Path $tmpPub)) {
New-Item -ItemType Directory -path $tmpPub
}
dotnet publish -c $BuildConfig osu.Desktop --self-contained -r win-x64 -o $tmpPub -verbosity:m /p:Version=$Version
vpk pack --packId jvnkosu.Client --packTitle "jvnkosu!lazer" --packVersion $Version --packDir ./pub --mainExe="osu!.exe"

149
README.md
View File

@@ -1,147 +1,40 @@
<p align="center">
<img width="500" alt="osu! logo" src="assets/lazer.png">
</p>
# jvnkosu! client
# osu!
A free-to-win rhythm game based on osu!(lazer). Click is just a *rhythm* away!
[![Build status](https://github.com/ppy/osu/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/ppy/osu/actions/workflows/ci.yml)
[![GitHub release](https://img.shields.io/github/release/ppy/osu.svg)](https://github.com/ppy/osu/releases/latest)
[![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu)
[![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/osu-web/localized.svg)](https://crowdin.com/project/osu-web)
## Disclaimer
A free-to-win rhythm game. Rhythm is just a *click* away!
*osu!* is a registered trademark of ppy Pty Ltd.
jvnkosu! is not affiliated with, or endorsed by ppy Pty Ltd., but makes use of its open-source components and resources.
This is the future and final iteration of the [osu!](https://osu.ppy.sh) game client which marks the beginning of an open era! Currently known by and released under the release codename "*lazer*". As in sharper than cutting-edge.
## License
Client source code is licensed under the MIT license, see the [LICENCE](LICENCE) file in repository root for more info.
## Status
Game assets are included as a NuGet package and licensed under the CC BY-NC 4.0, which prohibits commercial use. See [ppy/osu-resources](https://github.com/ppy/osu-resources) for more info.
This project is under constant development, but we do our best to keep things in a stable state. Players are encouraged to install from a release alongside their stable *osu!* client. This project will continue to evolve until we eventually reach the point where most users prefer it over the previous "osu!stable" release.
Registered trademarks "osu!" and "ppy" are property of ppy Pty Ltd., and protected by trademark law.
A few resources are available as starting points to getting involved and understanding the project:
## Compiling from source
Building jvnkosu! from source is pretty much possible (and welcome here).
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
- Track our current efforts [towards improving the game](https://github.com/orgs/ppy/projects/7/views/6).
First, you must have a desktop platform with [.NET Core SDK 8](https://dotnet.microsoft.com/download) installed. Windows, Linux, macOS should work well. You can check if you have the SDK installed by running `dotnet --version` in your command prompt/terminal.
## Running osu!
If you are just looking to give the game a whirl, you can grab the latest release for your platform:
### Latest release:
| [Windows 10+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 12+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 13.4+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) |
|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------- | ------------- | ------------- |
You can also generally download a version for your current device from the [osu! site](https://osu.ppy.sh/home/download).
If your platform is unsupported or not listed above, there is still a chance you can run the release or manually build it by following the instructions below.
**For iOS/iPadOS users**: The iOS testflight link fills up very fast (Apple has a hard limit of 10,000 users). We reset it occasionally. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements. Our goal is to get the game on mobile app stores very soon so we don't have to live with this limitation.
## Developing a custom ruleset
osu! is designed to allow user-created gameplay variations, called "rulesets". Building one of these allows a developer to harness the power of the osu! beatmap library, game engine, and general UX for a new style of gameplay. To get started working on a ruleset, we have some templates available [here](https://github.com/ppy/osu/tree/master/Templates).
You can see some examples of custom rulesets by visiting the [custom ruleset directory](https://github.com/ppy/osu/discussions/13096).
## Developing osu!
### Prerequisites
Please make sure you have the following prerequisites:
- 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/) 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.
### Downloading the source code
Clone the repository:
```shell
git clone https://github.com/ppy/osu
cd osu
Then, download the source code. You may download it as an archive and unzip it, but using [Git](https://git-scm.com/) instead is recommended:
```
git clone https://gitea.jvnko.boats/jvnkosu/client
```
To update the source code to the latest commit, run the following command inside the `osu` directory:
```shell
git pull
To **run** the project, switch to project's directory and run the following:
```
### Building
#### From an IDE
You should load the solution via one of the platform-specific `.slnf` files, rather than the main `.sln`. This will reduce dependencies and hide platforms that you don't care about. Valid `.slnf` files are:
- `osu.Desktop.slnf` (most common)
- `osu.Android.slnf`
- `osu.iOS.slnf`
Run configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `osu! (Tests)` project/configuration. More information on this is provided [below](#contributing).
To build for mobile platforms, you will likely need to run `sudo dotnet workload restore` if you haven't done so previously. This will install Android/iOS tooling required to complete the build.
#### From CLI
You can also build and run *osu!* from the command-line with a single command:
```shell
dotnet run --project osu.Desktop
```
When running locally to do any kind of performance testing, make sure to add `-c Release` to the build command, as the overhead of running with the default `Debug` configuration can be large (especially when testing with local framework modifications as below).
If the build fails, try to restore NuGet packages with `dotnet restore`.
### Testing with resource/framework modifications
Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be quickly achieved using included commands:
Windows:
```ps
UseLocalFramework.ps1
UseLocalResources.ps1
To **compile**:
```
dotnet build osu.Desktop
```
macOS / Linux:
To reduce performance overhead in custom builds, it's recommended to build with the `-c Release` flag, that will use the release profile and remove possibly unneeded debugging code.
```ps
UseLocalFramework.sh
UseLocalResources.sh
```
Note that these commands assume you have the relevant project(s) checked out in adjacent directories:
```
|- osu // this repository
|- osu-framework
|- osu-resources
```
### 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.
## 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. Please refer to the [contributing guidelines](CONTRIBUTING.md) to understand how to help in the most effective way possible.
If you wish to help with localisation efforts, head over to [crowdin](https://crowdin.com/project/osu-web).
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
*osu!*'s code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source.
Please note that this *does not cover* the usage of the "osu!" or "ppy" branding in any software, resources, advertising or promotion, as this is protected by trademark law.
Please also note that game resources are covered by a separate licence. Please see the [ppy/osu-resources](https://github.com/ppy/osu-resources) repository for clarifications.
### See the [original readme](README.original.md) for more info.

147
README.original.md Normal file
View File

@@ -0,0 +1,147 @@
<p align="center">
<img width="500" alt="osu! logo" src="assets/lazer.png">
</p>
# osu!
[![Build status](https://github.com/ppy/osu/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/ppy/osu/actions/workflows/ci.yml)
[![GitHub release](https://img.shields.io/github/release/ppy/osu.svg)](https://github.com/ppy/osu/releases/latest)
[![CodeFactor](https://www.codefactor.io/repository/github/ppy/osu/badge)](https://www.codefactor.io/repository/github/ppy/osu)
[![dev chat](https://discordapp.com/api/guilds/188630481301012481/widget.png?style=shield)](https://discord.gg/ppy)
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/osu-web/localized.svg)](https://crowdin.com/project/osu-web)
A free-to-win rhythm game. Rhythm is just a *click* away!
This is the future and final iteration of the [osu!](https://osu.ppy.sh) game client which marks the beginning of an open era! Currently known by and released under the release codename "*lazer*". As in sharper than cutting-edge.
## Status
This project is under constant development, but we do our best to keep things in a stable state. Players are encouraged to install from a release alongside their stable *osu!* client. This project will continue to evolve until we eventually reach the point where most users prefer it over the previous "osu!stable" release.
A few resources are available as starting points to getting involved and understanding the project:
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
- Track our current efforts [towards improving the game](https://github.com/orgs/ppy/projects/7/views/6).
## Running osu!
If you are just looking to give the game a whirl, you can grab the latest release for your platform:
### Latest release:
| [Windows 10+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | macOS 12+ ([Intel](https://github.com/ppy/osu/releases/latest/download/osu.app.Intel.zip), [Apple Silicon](https://github.com/ppy/osu/releases/latest/download/osu.app.Apple.Silicon.zip)) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 13.4+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) |
|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| ------------- | ------------- | ------------- |
You can also generally download a version for your current device from the [osu! site](https://osu.ppy.sh/home/download).
If your platform is unsupported or not listed above, there is still a chance you can run the release or manually build it by following the instructions below.
**For iOS/iPadOS users**: The iOS testflight link fills up very fast (Apple has a hard limit of 10,000 users). We reset it occasionally. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements. Our goal is to get the game on mobile app stores very soon so we don't have to live with this limitation.
## Developing a custom ruleset
osu! is designed to allow user-created gameplay variations, called "rulesets". Building one of these allows a developer to harness the power of the osu! beatmap library, game engine, and general UX for a new style of gameplay. To get started working on a ruleset, we have some templates available [here](https://github.com/ppy/osu/tree/master/Templates).
You can see some examples of custom rulesets by visiting the [custom ruleset directory](https://github.com/ppy/osu/discussions/13096).
## Developing osu!
### Prerequisites
Please make sure you have the following prerequisites:
- 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/) 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.
### Downloading the source code
Clone the repository:
```shell
git clone https://github.com/ppy/osu
cd osu
```
To update the source code to the latest commit, run the following command inside the `osu` directory:
```shell
git pull
```
### Building
#### From an IDE
You should load the solution via one of the platform-specific `.slnf` files, rather than the main `.sln`. This will reduce dependencies and hide platforms that you don't care about. Valid `.slnf` files are:
- `osu.Desktop.slnf` (most common)
- `osu.Android.slnf`
- `osu.iOS.slnf`
Run configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `osu! (Tests)` project/configuration. More information on this is provided [below](#contributing).
To build for mobile platforms, you will likely need to run `sudo dotnet workload restore` if you haven't done so previously. This will install Android/iOS tooling required to complete the build.
#### From CLI
You can also build and run *osu!* from the command-line with a single command:
```shell
dotnet run --project osu.Desktop
```
When running locally to do any kind of performance testing, make sure to add `-c Release` to the build command, as the overhead of running with the default `Debug` configuration can be large (especially when testing with local framework modifications as below).
If the build fails, try to restore NuGet packages with `dotnet restore`.
### Testing with resource/framework modifications
Sometimes it may be necessary to cross-test changes in [osu-resources](https://github.com/ppy/osu-resources) or [osu-framework](https://github.com/ppy/osu-framework). This can be quickly achieved using included commands:
Windows:
```ps
UseLocalFramework.ps1
UseLocalResources.ps1
```
macOS / Linux:
```ps
UseLocalFramework.sh
UseLocalResources.sh
```
Note that these commands assume you have the relevant project(s) checked out in adjacent directories:
```
|- osu // this repository
|- osu-framework
|- osu-resources
```
### 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.
## 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. Please refer to the [contributing guidelines](CONTRIBUTING.md) to understand how to help in the most effective way possible.
If you wish to help with localisation efforts, head over to [crowdin](https://crowdin.com/project/osu-web).
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
*osu!*'s code and framework are licensed under the [MIT licence](https://opensource.org/licenses/MIT). Please see [the licence file](LICENCE) for more information. [tl;dr](https://tldrlegal.com/license/mit-license) you can do whatever you want as long as you include the original copyright and license notice in any copy of the software/source.
Please note that this *does not cover* the usage of the "osu!" or "ppy" branding in any software, resources, advertising or promotion, as this is protected by trademark law.
Please also note that game resources are covered by a separate licence. Please see the [ppy/osu-resources](https://github.com/ppy/osu-resources) repository for clarifications.

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageType>Template</PackageType>
<PackageId>ppy.osu.Game.Templates</PackageId>
<PackageId>jvnkosu.Client.Templates</PackageId>
<Title>osu! templates</Title>
<Authors>ppy Pty Ltd</Authors>
<PackageLicenseUrl>https://github.com/ppy/osu/blob/master/LICENCE</PackageLicenseUrl>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="sh.ppy.osulazer" android:installLocation="auto">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="boats.jvnko.osu.android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="34" />
<application android:allowBackup="true"
android:supportsRtl="true"

View File

@@ -29,7 +29,7 @@ namespace osu.Desktop
{
internal partial class DiscordRichPresence : Component
{
private const string client_id = "1216669957799018608";
private const string client_id = "1440647613358800918";
private DiscordRpcClient client = null!;

View File

@@ -118,7 +118,7 @@ namespace osu.Desktop
if (IsPackageManaged)
return new NoActionUpdateManager();
return new VelopackUpdateManager();
return new VelopackUpdateManager(); // yay
}
public override bool RestartAppWhenExited()
@@ -148,7 +148,13 @@ namespace osu.Desktop
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
if (iconStream != null)
host.Window.SetIconFromStream(iconStream);
try
{
host.Window.SetIconFromStream(iconStream);
}
catch
{
}
host.Window.Title = Name;
}

View File

@@ -21,9 +21,9 @@ namespace osu.Desktop
public static class Program
{
#if DEBUG
private const string base_game_name = @"osu-development";
private const string base_game_name = @"jvnkosu-development";
#else
private const string base_game_name = @"osu";
private const string base_game_name = @"jvnkosu";
#endif
private static LegacyTcpIpcProvider? legacyIpc;
@@ -44,7 +44,7 @@ namespace osu.Desktop
// While .NET 8 only supports Windows 10 and above, running on Windows 7/8.1 may still work. We are limited by realm currently, as they choose to only support 8.1 and higher.
// See https://www.mongodb.com/docs/realm/sdk/dotnet/compatibility/
if (windowsVersion.Major < 6 || (windowsVersion.Major == 6 && windowsVersion.Minor <= 2))
if (windowsVersion.Major < 6)
{
unsafe
{
@@ -53,13 +53,26 @@ namespace osu.Desktop
// We could also better detect compatibility mode if required:
// https://stackoverflow.com/questions/10744651/how-i-can-detect-if-my-application-is-running-under-compatibility-mode#comment58183249_10744730
SDL3.SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags.SDL_MESSAGEBOX_ERROR,
"Your operating system is too old to run osu!"u8,
"This version of osu! requires at least Windows 8.1 to run.\n"u8
+ "Please upgrade your operating system or consider using an older version of osu!.\n\n"u8
+ "If you are running a newer version of windows, please check you don't have \"Compatibility mode\" turned on for osu!"u8, null);
"Your operating system is too old to run this game!"u8,
"This version of the game requires at least Windows 8.1 to run reliably.\n"u8
+ "You may try to run it on Windows 8 or older, but it's not guaranteed to actually work.\n\n"u8
+ "Please upgrade your operating system or consider using an older game version.\n\n"u8
+ "If you are running a newer version of Windows, please check you don't have \"Compatibility mode\" turned on for the game's executable."u8, null);
return;
}
}
if (windowsVersion.Major == 6 && windowsVersion.Minor <= 2)
{
unsafe
{
SDL3.SDL_ShowSimpleMessageBox(SDL_MessageBoxFlags.SDL_MESSAGEBOX_WARNING,
"Your operating system is too old to run this game!"u8,
"While the version of Windows you're using may be able to launch it, it's likely to work unreliably and crash.\n"u8
+ "Please upgrade your operating system or consider using an older game version.\n\n"u8
+ "If you are running a newer version of Windows, please check you don't have \"Compatibility mode\" turned on for the game's executable."u8, null);
}
}
}
// NVIDIA profiles are based on the executable name of a process.
@@ -208,9 +221,10 @@ namespace osu.Desktop
[SupportedOSPlatform("windows")]
private static void configureWindows(VelopackApp app)
{
app.OnFirstRun(_ => WindowsAssociationManager.InstallAssociations());
app.OnAfterUpdateFastCallback(_ => WindowsAssociationManager.UpdateAssociations());
app.OnBeforeUninstallFastCallback(_ => WindowsAssociationManager.UninstallAssociations());
// we do not want associations here, as that breaks official lazer's associations
// app.OnFirstRun(_ => WindowsAssociationManager.InstallAssociations());
// app.OnAfterUpdateFastCallback(_ => WindowsAssociationManager.UpdateAssociations());
// app.OnBeforeUninstallFastCallback(_ => WindowsAssociationManager.UninstallAssociations());
}
}
}

View File

@@ -55,7 +55,7 @@ namespace osu.Desktop.Updater
try
{
IUpdateSource updateSource = new GithubSource(@"https://github.com/ppy/osu", null, ReleaseStream.Value == Game.Configuration.ReleaseStream.Tachyon);
IUpdateSource updateSource = new GiteaSource(@"https://gitea.jvnko.boats/jvnkosu/client", null, ReleaseStream.Value == Game.Configuration.ReleaseStream.Tachyon);
Velopack.UpdateManager updateManager = new Velopack.UpdateManager(updateSource, new UpdateOptions
{
AllowVersionDowngrade = true

View File

@@ -53,8 +53,8 @@ namespace osu.Desktop.Windows
private static readonly UriAssociation[] uri_associations =
{
new UriAssociation(@"osu", WindowsAssociationManagerStrings.OsuProtocol, Icons.Lazer),
new UriAssociation(@"osump", WindowsAssociationManagerStrings.OsuMultiplayer, Icons.Lazer),
new UriAssociation(@"jvnkosu", WindowsAssociationManagerStrings.OsuProtocol, Icons.Lazer),
new UriAssociation(@"jvnkosump", WindowsAssociationManagerStrings.OsuMultiplayer, Icons.Lazer),
};
/// <summary>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 401 KiB

View File

@@ -3,11 +3,11 @@
<TargetFramework>net8.0</TargetFramework>
<OutputType>WinExe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>A free-to-win rhythm game. Rhythm is just a *click* away!</Description>
<Description>A free-to-win rhythm game based on osu!(lazer). Click is just a *rhythm* away!</Description>
<AssemblyName>osu!</AssemblyName>
<AssemblyTitle>osu!(lazer)</AssemblyTitle>
<Title>osu!</Title>
<Product>osu!(lazer)</Product>
<AssemblyTitle>jvnkosu!</AssemblyTitle>
<Title>jvnkosu!</Title>
<Product>jvnkosu!</Product>
<ApplicationIcon>lazer.ico</ApplicationIcon>
<Version>0.0.0</Version>
<FileVersion>0.0.0</FileVersion>

View File

@@ -3,16 +3,19 @@
<metadata>
<id>osulazer</id>
<version>0.0.0</version>
<title>osu!</title>
<authors>ppy Pty Ltd</authors>
<title>jvnkosu!</title>
<authors>ppy Pty Ltd., jvnkosu! team</authors>
<owners>Dean Herbert</owners>
<projectUrl>https://osu.ppy.sh/</projectUrl>
<projectUrl>https://osu.jvnko.boats/</projectUrl>
<iconUrl>https://github.com/ppy/osu/blob/master/assets/lazer-nuget.png?raw=true</iconUrl>
<icon>icon.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>A free-to-win rhythm game. Rhythm is just a *click* away!</description>
<description>A free-to-win rhythm game based on osu!(lazer). Click is just a *rhythm* away!</description>
<releaseNotes>testing</releaseNotes>
<copyright>Copyright (c) 2025 ppy Pty Ltd</copyright>
<copyright>
Copyright (c) 2025 ppy Pty Ltd
Copyright (c) 2025 jvnkosu! team
</copyright>
<language>en-AU</language>
</metadata>
<files>

View File

@@ -72,9 +72,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
leaderboard.Origin = Anchor.CentreLeft;
leaderboard.X = 10;
}
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
Children = new Drawable[]

View File

@@ -8,7 +8,7 @@
<PropertyGroup Label="Nuget">
<Title>osu!catch (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Catch</PackageId>
<PackageId>jvnkosu.Client.Rulesets.Catch</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>

View File

@@ -14,8 +14,8 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => Name;
public abstract int KeyCount { get; }
public override ModType Type => ModType.Conversion;
public override double ScoreMultiplier => 0.9;
public override bool Ranked => UsesDefaultConfiguration;
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter)
{

View File

@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mania.Mods
typeof(ManiaModFadeIn)
}).ToArray();
public override bool Ranked => false;
public override bool Ranked => true;
public override bool ValidForFreestyleAsRequiredMod => false;

View File

@@ -13,8 +13,13 @@ namespace osu.Game.Rulesets.Mania.Mods
MinValue = 0,
MaxValue = 10,
// Use larger extended limits for mania to include OD values that occur with EZ or HR enabled
#if !DEBUG
ExtendedMaxValue = 15,
ExtendedMinValue = -15,
#else
ExtendedMinValue = -250,
ExtendedMaxValue = 50,
#endif
ReadCurrentFromDifficulty = diff => diff.OverallDifficulty,
};
}

View File

@@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModHardRock : ModHardRock, IApplicableToHitObject
{
public override double ScoreMultiplier => 1;
public override bool Ranked => false;
public override bool Ranked => true;
public const double HIT_WINDOW_DIFFICULTY_MULTIPLIER = 1.4;

View File

@@ -14,6 +14,5 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => "1K";
public override IconUsage? Icon => OsuIcon.ModOneKey;
public override LocalisableString Description => @"Play with one key.";
public override bool Ranked => false;
}
}

View File

@@ -14,6 +14,5 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => "10K";
public override IconUsage? Icon => OsuIcon.ModTenKeys;
public override LocalisableString Description => @"Play with ten keys.";
public override bool Ranked => false;
}
}

View File

@@ -14,6 +14,5 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => "2K";
public override IconUsage? Icon => OsuIcon.ModTwoKeys;
public override LocalisableString Description => @"Play with two keys.";
public override bool Ranked => false;
}
}

View File

@@ -14,6 +14,5 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Acronym => "3K";
public override IconUsage? Icon => OsuIcon.ModThreeKeys;
public override LocalisableString Description => @"Play with three keys.";
public override bool Ranked => false;
}
}

View File

@@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public class ManiaModMirror : ModMirror, IApplicableToBeatmap
{
public override LocalisableString Description => "Notes are flipped horizontally.";
public override bool Ranked => UsesDefaultConfiguration;
public override bool Ranked => true;
public void ApplyToBeatmap(IBeatmap beatmap)
{

View File

@@ -57,9 +57,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
if (spectatorList != null)
spectatorList.Position = new Vector2(36, -66);
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
new DrawableGameplayLeaderboard(),

View File

@@ -122,9 +122,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
leaderboard.Origin = Anchor.CentreLeft;
leaderboard.X = 10;
}
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
new LegacyManiaComboCounter(),

View File

@@ -8,7 +8,7 @@
<PropertyGroup Label="Nuget">
<Title>osu!mania (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Mania</PackageId>
<PackageId>jvnkosu.Client.Rulesets.Mania</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>

View File

@@ -14,7 +14,13 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModMagnetised), typeof(OsuModRepel), typeof(OsuModAutopilot), typeof(OsuModSpunOut), typeof(OsuModAlternate), typeof(OsuModSingleTap) }).ToArray();
#if !DEBUG
private string username = "Autoplay";
#else
private string username = "Chicony";
#endif
public override ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList<Mod> mods)
=> new ModReplayData(new OsuAutoGenerator(beatmap, mods).Generate(), new ModCreatedUser { Username = "Autoplay" });
=> new ModReplayData(new OsuAutoGenerator(beatmap, mods).Generate(), new ModCreatedUser { Username = username });
}
}

View File

@@ -16,13 +16,19 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public partial class OsuModDifficultyAdjust : ModDifficultyAdjust
{
[SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1, SettingControlType = typeof(DifficultyAdjustSettingsControl))]
public DifficultyBindable CircleSize { get; } = new DifficultyBindable
{
Precision = 0.1f,
MinValue = 0,
MaxValue = 10,
#if !DEBUG
ExtendedMaxValue = 11,
#else
ExtendedMinValue = -250,
ExtendedMaxValue = 13,
#endif
ReadCurrentFromDifficulty = diff => diff.CircleSize,
};
@@ -32,8 +38,13 @@ namespace osu.Game.Rulesets.Osu.Mods
Precision = 0.1f,
MinValue = 0,
MaxValue = 10,
#if !DEBUG
ExtendedMinValue = -10,
ExtendedMaxValue = 11,
#else
ExtendedMinValue = -250,
ExtendedMaxValue = 13,
#endif
ReadCurrentFromDifficulty = diff => diff.ApproachRate,
};

View File

@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override LocalisableString Description => @"Spinners will be automatically completed.";
public override double ScoreMultiplier => 0.9;
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(OsuModAutopilot), typeof(OsuModTargetPractice) };
public override bool Ranked => UsesDefaultConfiguration;
public override bool Ranked => true;
public void ApplyToDrawableHitObject(DrawableHitObject hitObject)
{

View File

@@ -10,6 +10,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public class OsuModTouchDevice : ModTouchDevice
{
public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(OsuModAutopilot), typeof(OsuModBloom) }).ToArray();
public override bool Ranked => UsesDefaultConfiguration;
public override bool Ranked => true;
}
}

View File

@@ -230,6 +230,11 @@ namespace osu.Game.Rulesets.Osu
new ModScoreV2(),
};
case ModType.Special:
#if DEBUG
return Array.Empty<Mod>();
#endif
default:
return Array.Empty<Mod>();
}
@@ -249,7 +254,11 @@ namespace osu.Game.Rulesets.Osu
public override string ShortName => SHORT_NAME;
#if !DEBUG
public override string PlayingVerb => "Clicking circles";
#else
public override string PlayingVerb => "Debugging circles";
#endif
public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this);

View File

@@ -103,9 +103,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
leaderboard.Origin = Anchor.BottomLeft;
leaderboard.Position = pos;
}
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
Children = new Drawable[]

View File

@@ -49,18 +49,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
/// </summary>
protected bool AllowPartRotation { get; set; }
private Vector2 cursorScale;
public Vector2 CursorScale
{
get => cursorScale;
set
{
cursorScale = value;
Invalidate(Invalidation.DrawNode);
}
}
/// <summary>
/// The trail part texture origin.
/// </summary>
@@ -245,7 +233,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private float time;
private float fadeExponent;
private float angle;
private Vector2 cursorScale;
private readonly TrailPart[] parts = new TrailPart[max_sprites];
private Vector2 originPosition;
@@ -266,7 +253,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
time = Source.time;
fadeExponent = Source.FadeExponent;
angle = Source.AllowPartRotation ? float.DegreesToRadians(Source.PartRotation) : 0;
cursorScale = Source.cursorScale;
originPosition = Vector2.Zero;
@@ -321,9 +307,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Add(new TexturedTrailVertex
{
Position = rotateAround(
new Vector2(
part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X * cursorScale.X,
part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y * cursorScale.Y),
new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y),
part.Position, sin, cos),
TexturePosition = textureRect.BottomLeft,
TextureRect = new Vector4(0, 0, 1, 1),
@@ -334,10 +318,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Add(new TexturedTrailVertex
{
Position = rotateAround(
new Vector2(
part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X * cursorScale.X,
part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y * cursorScale.Y),
part.Position, sin, cos),
new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X,
part.Position.Y + texture.DisplayHeight * (1 - originPosition.Y) * part.Scale.Y), part.Position, sin, cos),
TexturePosition = textureRect.BottomRight,
TextureRect = new Vector4(0, 0, 1, 1),
Colour = DrawColourInfo.Colour.BottomRight.Linear,
@@ -347,9 +329,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Add(new TexturedTrailVertex
{
Position = rotateAround(
new Vector2(
part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X * cursorScale.X,
part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y * cursorScale.Y),
new Vector2(part.Position.X + texture.DisplayWidth * (1 - originPosition.X) * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y),
part.Position, sin, cos),
TexturePosition = textureRect.TopRight,
TextureRect = new Vector4(0, 0, 1, 1),
@@ -360,9 +340,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
vertexBatch.Add(new TexturedTrailVertex
{
Position = rotateAround(
new Vector2(
part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X * cursorScale.X,
part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y * cursorScale.Y),
new Vector2(part.Position.X - texture.DisplayWidth * originPosition.X * part.Scale.X, part.Position.Y - texture.DisplayHeight * originPosition.Y * part.Scale.Y),
part.Position, sin, cos),
TexturePosition = textureRect.TopLeft,
TextureRect = new Vector4(0, 0, 1, 1),

View File

@@ -64,14 +64,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
var newScale = new Vector2(e.NewValue);
rippleVisualiser.CursorScale = newScale;
updateTrailScale();
cursorTrail.Scale = newScale;
}, true);
cursorTrail.OnSkinChanged += updateTrailScale;
}
private void updateTrailScale()
{
if (cursorTrail.Drawable is CursorTrail trail) trail.CursorScale = new Vector2(ActiveCursor.CursorScale.Value);
}
private int downCount;

View File

@@ -8,7 +8,7 @@
<PropertyGroup Label="Nuget">
<Title>osu! (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Osu</PackageId>
<PackageId>jvnkosu.Client.Rulesets.Osu</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>

View File

@@ -51,9 +51,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
spectatorList.Anchor = Anchor.BottomLeft;
spectatorList.Origin = Anchor.TopLeft;
}
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
RelativeSizeAxes = Axes.Both,

View File

@@ -51,9 +51,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Default
spectatorList.Origin = Anchor.TopLeft;
spectatorList.Position = new Vector2(320, -280);
}
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
RelativeSizeAxes = Axes.Both,

View File

@@ -79,9 +79,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
spectatorList.Origin = Anchor.TopLeft;
spectatorList.Position = pos;
}
foreach (var d in container.OfType<ISerialisableDrawable>())
d.UsesFixedAnchor = true;
})
{
new LegacyDefaultComboCounter(),

View File

@@ -8,7 +8,7 @@
<PropertyGroup Label="Nuget">
<Title>osu!taiko (ruleset)</Title>
<PackageId>ppy.osu.Game.Rulesets.Taiko</PackageId>
<PackageId>jvnkosu.Client.Rulesets.Taiko</PackageId>
<IsPackable>true</IsPackable>
</PropertyGroup>

View File

@@ -17,7 +17,7 @@ namespace osu.Game.Tests.Chat
public void OneTimeSetUp()
{
originalWebsiteRootUrl = MessageFormatter.WebsiteRootUrl;
MessageFormatter.WebsiteRootUrl = "dev.ppy.sh";
MessageFormatter.WebsiteRootUrl = "osu.jvnko.boats";
}
[OneTimeTearDown]
@@ -47,11 +47,11 @@ namespace osu.Game.Tests.Chat
[Test]
public void TestSupportedProtocolLinkParsing()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "forgotspacehttps://dev.ppy.sh joinmyosump://12345 jointheosu://chan/#english" });
Message result = MessageFormatter.FormatMessage(new Message { Content = "forgotspacehttps://osu.jvnko.boats joinmyjvnkosump://12345 jointhejvnkosu://chan/#english" });
Assert.AreEqual("https://dev.ppy.sh", result.Links[0].Url);
Assert.AreEqual("osump://12345", result.Links[1].Url);
Assert.AreEqual("osu://chan/#english", result.Links[2].Url);
Assert.AreEqual("https://osu.jvnko.boats", result.Links[0].Url);
Assert.AreEqual("jvnkosump://12345", result.Links[1].Url);
Assert.AreEqual("jvnkosu://chan/#english", result.Links[2].Url);
}
[Test]
@@ -66,15 +66,15 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(36, result.Links[0].Length);
}
[TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123#osu/456?whatever")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://dev.ppy.sh/beatmapsets/123/456")]
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc/def", "https://dev.ppy.sh/beatmapsets/abc/def")]
[TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123")]
[TestCase(LinkAction.OpenBeatmapSet, "123", "https://dev.ppy.sh/beatmapsets/123/whatever")]
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/abc", "https://dev.ppy.sh/beatmapsets/abc")]
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/discussions", "https://dev.ppy.sh/beatmapsets/discussions")]
[TestCase(LinkAction.External, "https://dev.ppy.sh/beatmapsets/discussions/123", "https://dev.ppy.sh/beatmapsets/discussions/123")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://osu.jvnko.boats/beatmapsets/123#osu/456")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://osu.jvnko.boats/beatmapsets/123#osu/456?whatever")]
[TestCase(LinkAction.OpenBeatmap, "456", "https://osu.jvnko.boats/beatmapsets/123/456")]
[TestCase(LinkAction.External, "https://osu.jvnko.boats/beatmapsets/abc/def", "https://osu.jvnko.boats/beatmapsets/abc/def")]
[TestCase(LinkAction.OpenBeatmapSet, "123", "https://osu.jvnko.boats/beatmapsets/123")]
[TestCase(LinkAction.OpenBeatmapSet, "123", "https://osu.jvnko.boats/beatmapsets/123/whatever")]
[TestCase(LinkAction.External, "https://osu.jvnko.boats/beatmapsets/abc", "https://osu.jvnko.boats/beatmapsets/abc")]
[TestCase(LinkAction.External, "https://osu.jvnko.boats/beatmapsets/discussions", "https://osu.jvnko.boats/beatmapsets/discussions")]
[TestCase(LinkAction.External, "https://osu.jvnko.boats/beatmapsets/discussions/123", "https://osu.jvnko.boats/beatmapsets/discussions/123")]
public void TestBeatmapLinks(LinkAction expectedAction, string expectedArg, string link)
{
Message result = MessageFormatter.FormatMessage(new Message { Content = link });
@@ -150,7 +150,7 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual("This is a Wiki Link.", result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
Assert.AreEqual("https://osu.jvnko.boats/wiki/Wiki Link", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(9, result.Links[0].Length);
}
@@ -163,15 +163,15 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual("This is a Wiki Link Wiki:LinkWiki.Link.", result.DisplayContent);
Assert.AreEqual(3, result.Links.Count);
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki Link", result.Links[0].Url);
Assert.AreEqual("https://osu.jvnko.boats/wiki/Wiki Link", result.Links[0].Url);
Assert.AreEqual(10, result.Links[0].Index);
Assert.AreEqual(9, result.Links[0].Length);
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki:Link", result.Links[1].Url);
Assert.AreEqual("https://osu.jvnko.boats/wiki/Wiki:Link", result.Links[1].Url);
Assert.AreEqual(20, result.Links[1].Index);
Assert.AreEqual(9, result.Links[1].Length);
Assert.AreEqual("https://dev.ppy.sh/wiki/Wiki.Link", result.Links[2].Url);
Assert.AreEqual("https://osu.jvnko.boats/wiki/Wiki.Link", result.Links[2].Url);
Assert.AreEqual(29, result.Links[2].Index);
Assert.AreEqual(9, result.Links[2].Length);
}
@@ -452,7 +452,7 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual($"{OsuGameBase.OSU_PROTOCOL}chan/#english", result.Links[0].Url);
Assert.AreEqual(26, result.Links[0].Index);
Assert.AreEqual(19, result.Links[0].Length);
Assert.AreEqual(23, result.Links[0].Length);
result = MessageFormatter.FormatMessage(new Message { Content = $"This is a [custom protocol]({OsuGameBase.OSU_PROTOCOL}chan/#english)." });
@@ -467,13 +467,13 @@ namespace osu.Game.Tests.Chat
[Test]
public void TestOsuMpProtocol()
{
Message result = MessageFormatter.FormatMessage(new Message { Content = "Join my multiplayer game osump://12346." });
Message result = MessageFormatter.FormatMessage(new Message { Content = "Join my multiplayer game jvnkosump://12346." });
Assert.AreEqual(result.Content, result.DisplayContent);
Assert.AreEqual(1, result.Links.Count);
Assert.AreEqual("osump://12346", result.Links[0].Url);
Assert.AreEqual("jvnkosump://12346", result.Links[0].Url);
Assert.AreEqual(25, result.Links[0].Index);
Assert.AreEqual(13, result.Links[0].Length);
Assert.AreEqual(17, result.Links[0].Length);
}
[Test]
@@ -499,7 +499,7 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual("This is a simple test with some [traps] and wiki links. Don't forget to visit https://osu.ppy.sh now![emoji]", result.DisplayContent);
Assert.AreEqual(4, result.Links.Count);
Link f = result.Links.Find(l => l.Url == "https://dev.ppy.sh/wiki/wiki links");
Link f = result.Links.Find(l => l.Url == "https://osu.jvnko.boats/wiki/wiki links");
Assert.That(f, Is.Not.Null);
Assert.AreEqual(44, f.Index);
Assert.AreEqual(10, f.Length);
@@ -554,8 +554,8 @@ namespace osu.Game.Tests.Chat
Assert.AreEqual("/relative", result.Argument);
}
[TestCase("https://dev.ppy.sh/home/changelog", "")]
[TestCase("https://dev.ppy.sh/home/changelog/lazer/2021.1012", "lazer/2021.1012")]
[TestCase("https://osu.jvnko.boats/home/changelog", "")]
[TestCase("https://osu.jvnko.boats/home/changelog/lazer/2021.1012", "lazer/2021.1012")]
public void TestChangelogLinks(string link, string expectedArg)
{
LinkDetails result = MessageFormatter.GetLinkDetails(link);

View File

@@ -134,10 +134,12 @@ namespace osu.Game.Tests.Mods
var mod = (OsuModDifficultyAdjust)apiMod.ToMod(ruleset);
// WARNING: this only makes sense for debug builds which have very extended limits
// release builds still use sane values
Assert.Multiple(() =>
{
Assert.That(mod.CircleSize.Value, Is.GreaterThanOrEqualTo(0).And.LessThanOrEqualTo(11));
Assert.That(mod.ApproachRate.Value, Is.GreaterThanOrEqualTo(-10).And.LessThanOrEqualTo(11));
Assert.That(mod.CircleSize.Value, Is.GreaterThanOrEqualTo(-250).And.LessThanOrEqualTo(13));
Assert.That(mod.ApproachRate.Value, Is.GreaterThanOrEqualTo(-250).And.LessThanOrEqualTo(13));
});
}

View File

@@ -39,7 +39,7 @@ namespace osu.Game.Tests.Online
Assert.NotNull(converted);
Assert.That(converted, Is.TypeOf(typeof(UnknownMod)));
Assert.That(converted.Type, Is.EqualTo(ModType.System));
Assert.That(converted.Acronym, Is.EqualTo("WNG??"));
Assert.That(converted.Acronym, Is.EqualTo("WNG!"));
}
[Test]

View File

@@ -16,6 +16,7 @@ using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Formats;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.IO;
using osu.Game.IO.Archives;
@@ -206,7 +207,7 @@ namespace osu.Game.Tests.Online
{
}
protected override BeatmapImporter CreateBeatmapImporter(Storage storage, RealmAccess realm)
protected override BeatmapImporter CreateBeatmapImporter(Storage storage, RealmAccess realm, OsuConfigManager? config = null)
{
return new TestBeatmapImporter(this, storage, realm);
}
@@ -216,7 +217,7 @@ namespace osu.Game.Tests.Online
private readonly TestBeatmapManager testBeatmapManager;
public TestBeatmapImporter(TestBeatmapManager testBeatmapManager, Storage storage, RealmAccess databaseAccess)
: base(storage, databaseAccess)
: base(storage, databaseAccess, null)
{
this.testBeatmapManager = testBeatmapManager;
}
@@ -224,7 +225,7 @@ namespace osu.Game.Tests.Online
public override Live<BeatmapSetInfo>? ImportModel(BeatmapSetInfo item, ArchiveReader? archive = null, ImportParameters parameters = default,
CancellationToken cancellationToken = default)
{
if (!testBeatmapManager.AllowImport.Wait(TimeSpan.FromSeconds(10), cancellationToken))
if (!testBeatmapManager.AllowImport.Wait(TimeSpan.FromSeconds(30), cancellationToken))
throw new TimeoutException("Timeout waiting for import to be allowed.");
return testBeatmapManager.CurrentImport = base.ImportModel(item, archive, parameters, cancellationToken);

View File

@@ -79,10 +79,10 @@ namespace osu.Game.Tests.Skins
"Archives/modified-argon-20250424.osk",
// Covers "Argon" unstable rate counter
"Archives/modified-argon-20250809.osk",
// Covers legacy style performance points counter
"Archives/modified-classic-20250827.osk",
// Covers "Argon" judgement counter
"Archives/modified-argon-20250308.osk",
// Covers "Argon" clicks/s counter, longest combo counter, skinnable SR display and beatmap status pill
"Archives/modified-argon-20251215-jvnkosu.osk",
};
/// <summary>

View File

@@ -1,209 +1,209 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
// // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// // See the LICENCE file in the repository root for full licence text.
#nullable disable
// #nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Textures;
using osu.Game.Configuration;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
// using System;
// using System.Collections.Generic;
// using System.Linq;
// using NUnit.Framework;
// using osu.Framework.Allocation;
// using osu.Framework.Graphics;
// using osu.Framework.Graphics.Containers;
// using osu.Framework.Graphics.Rendering;
// using osu.Framework.Graphics.Textures;
// using osu.Game.Configuration;
// using osu.Game.Graphics.Backgrounds;
// using osu.Game.Online.API;
// using osu.Game.Online.API.Requests;
// using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Tests.Visual.Background
{
public partial class TestSceneSeasonalBackgroundLoader : ScreenTestScene
{
[Resolved]
private OsuConfigManager config { get; set; }
// namespace osu.Game.Tests.Visual.Background
// {
// public partial class TestSceneSeasonalBackgroundLoader : ScreenTestScene
// {
// [Resolved]
// private OsuConfigManager config { get; set; }
[Resolved]
private SessionStatics statics { get; set; }
// [Resolved]
// private SessionStatics statics { get; set; }
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
// private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
private LookupLoggingTextureStore textureStore;
private SeasonalBackgroundLoader backgroundLoader;
private Container backgroundContainer;
// private LookupLoggingTextureStore textureStore;
// private SeasonalBackgroundLoader backgroundLoader;
// private Container backgroundContainer;
// in real usages these would be online URLs, but correct execution of this test
// shouldn't be coupled to existence of online assets.
private static readonly List<string> seasonal_background_urls = new List<string>
{
"Backgrounds/bg2",
"Backgrounds/bg4",
"Backgrounds/bg3"
};
// // in real usages these would be online URLs, but correct execution of this test
// // shouldn't be coupled to existence of online assets.
// private static readonly List<string> seasonal_background_urls = new List<string>
// {
// "Backgrounds/bg2",
// "Backgrounds/bg4",
// "Backgrounds/bg3"
// };
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
// protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
// {
// var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
textureStore = new LookupLoggingTextureStore(dependencies.Get<IRenderer>());
dependencies.CacheAs(typeof(LargeTextureStore), textureStore);
// textureStore = new LookupLoggingTextureStore(dependencies.Get<IRenderer>());
// dependencies.CacheAs(typeof(LargeTextureStore), textureStore);
return dependencies;
}
// return dependencies;
// }
[BackgroundDependencyLoader]
private void load(LargeTextureStore wrappedStore)
{
textureStore.AddStore(wrappedStore);
// [BackgroundDependencyLoader]
// private void load(LargeTextureStore wrappedStore)
// {
// textureStore.AddStore(wrappedStore);
Child = new DependencyProvidingContainer
{
CachedDependencies = new (Type, object)[]
{
(typeof(LargeTextureStore), textureStore)
},
Child = backgroundContainer = new Container
{
RelativeSizeAxes = Axes.Both
}
};
}
// Child = new DependencyProvidingContainer
// {
// CachedDependencies = new (Type, object)[]
// {
// (typeof(LargeTextureStore), textureStore)
// },
// Child = backgroundContainer = new Container
// {
// RelativeSizeAxes = Axes.Both
// }
// };
// }
[SetUp]
public void SetUp() => Schedule(() =>
{
// reset API response in statics to avoid test crosstalk.
statics.SetValue<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
textureStore.PerformedLookups.Clear();
dummyAPI.SetState(APIState.Online);
// [SetUp]
// public void SetUp() => Schedule(() =>
// {
// // reset API response in statics to avoid test crosstalk.
// statics.SetValue<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
// textureStore.PerformedLookups.Clear();
// dummyAPI.SetState(APIState.Online);
backgroundContainer.Clear();
});
// backgroundContainer.Clear();
// });
[TestCase(-5)]
[TestCase(5)]
public void TestAlwaysSeasonal(int daysOffset)
{
registerBackgroundsResponse(DateTimeOffset.Now.AddDays(daysOffset));
setSeasonalBackgroundMode(SeasonalBackgroundMode.Always);
// [TestCase(-5)]
// [TestCase(5)]
// public void TestAlwaysSeasonal(int daysOffset)
// {
// registerBackgroundsResponse(DateTimeOffset.Now.AddDays(daysOffset));
// setSeasonalBackgroundMode(SeasonalBackgroundMode.Always);
createLoader();
// createLoader();
for (int i = 0; i < 4; ++i)
loadNextBackground();
// for (int i = 0; i < 4; ++i)
// loadNextBackground();
AddAssert("all backgrounds cycled", () => new HashSet<string>(textureStore.PerformedLookups).SetEquals(seasonal_background_urls));
}
// AddAssert("all backgrounds cycled", () => new HashSet<string>(textureStore.PerformedLookups).SetEquals(seasonal_background_urls));
// }
[TestCase(-5)]
[TestCase(5)]
public void TestNeverSeasonal(int daysOffset)
{
registerBackgroundsResponse(DateTimeOffset.Now.AddDays(daysOffset));
setSeasonalBackgroundMode(SeasonalBackgroundMode.Never);
// [TestCase(-5)]
// [TestCase(5)]
// public void TestNeverSeasonal(int daysOffset)
// {
// registerBackgroundsResponse(DateTimeOffset.Now.AddDays(daysOffset));
// setSeasonalBackgroundMode(SeasonalBackgroundMode.Never);
createLoader();
// createLoader();
assertNoBackgrounds();
}
// assertNoBackgrounds();
// }
[Test]
public void TestSometimesInSeason()
{
registerBackgroundsResponse(DateTimeOffset.Now.AddDays(5));
setSeasonalBackgroundMode(SeasonalBackgroundMode.Sometimes);
// [Test]
// public void TestSometimesInSeason()
// {
// registerBackgroundsResponse(DateTimeOffset.Now.AddDays(5));
// setSeasonalBackgroundMode(SeasonalBackgroundMode.Sometimes);
createLoader();
// createLoader();
assertAnyBackground();
}
// assertAnyBackground();
// }
[Test]
public void TestSometimesOutOfSeason()
{
registerBackgroundsResponse(DateTimeOffset.Now.AddDays(-10));
setSeasonalBackgroundMode(SeasonalBackgroundMode.Sometimes);
// [Test]
// public void TestSometimesOutOfSeason()
// {
// registerBackgroundsResponse(DateTimeOffset.Now.AddDays(-10));
// setSeasonalBackgroundMode(SeasonalBackgroundMode.Sometimes);
createLoader();
// createLoader();
assertNoBackgrounds();
}
// assertNoBackgrounds();
// }
private void registerBackgroundsResponse(DateTimeOffset endDate)
=> AddStep("setup request handler", () =>
{
dummyAPI.HandleRequest = request =>
{
if (dummyAPI.State.Value != APIState.Online || !(request is GetSeasonalBackgroundsRequest backgroundsRequest))
return false;
// private void registerBackgroundsResponse(DateTimeOffset endDate)
// => AddStep("setup request handler", () =>
// {
// dummyAPI.HandleRequest = request =>
// {
// if (dummyAPI.State.Value != APIState.Online || !(request is GetSeasonalBackgroundsRequest backgroundsRequest))
// return false;
backgroundsRequest.TriggerSuccess(new APISeasonalBackgrounds
{
Backgrounds = seasonal_background_urls.Select(url => new APISeasonalBackground { Url = url }).ToList(),
EndDate = endDate
});
// backgroundsRequest.TriggerSuccess(new APISeasonalBackgrounds
// {
// Backgrounds = seasonal_background_urls.Select(url => new APISeasonalBackground { Url = url }).ToList(),
// EndDate = endDate
// });
return true;
};
});
// return true;
// };
// });
private void setSeasonalBackgroundMode(SeasonalBackgroundMode mode)
=> AddStep($"set seasonal mode to {mode}", () => config.SetValue(OsuSetting.SeasonalBackgroundMode, mode));
// private void setSeasonalBackgroundMode(SeasonalBackgroundMode mode)
// => AddStep($"set seasonal mode to {mode}", () => config.SetValue(OsuSetting.SeasonalBackgroundMode, mode));
private void createLoader()
=> AddStep("create loader", () =>
{
if (backgroundLoader != null)
Remove(backgroundLoader, true);
// private void createLoader()
// => AddStep("create loader", () =>
// {
// if (backgroundLoader != null)
// Remove(backgroundLoader, true);
Add(backgroundLoader = new SeasonalBackgroundLoader());
});
// Add(backgroundLoader = new SeasonalBackgroundLoader());
// });
private void loadNextBackground()
{
SeasonalBackground previousBackground = null;
SeasonalBackground background = null;
// private void loadNextBackground()
// {
// SeasonalBackground previousBackground = null;
// SeasonalBackground background = null;
AddStep("create next background", () =>
{
previousBackground = (SeasonalBackground)backgroundContainer.SingleOrDefault();
background = backgroundLoader.LoadNextBackground();
if (background != null)
LoadComponentAsync(background, bg => backgroundContainer.Child = bg);
});
// AddStep("create next background", () =>
// {
// previousBackground = (SeasonalBackground)backgroundContainer.SingleOrDefault();
// background = backgroundLoader.LoadNextBackground();
// if (background != null)
// LoadComponentAsync(background, bg => backgroundContainer.Child = bg);
// });
AddUntilStep("background loaded", () => background.IsLoaded);
AddAssert("background is different", () => !background.Equals(previousBackground));
}
// AddUntilStep("background loaded", () => background.IsLoaded);
// AddAssert("background is different", () => !background.Equals(previousBackground));
// }
private void assertAnyBackground()
{
loadNextBackground();
AddAssert("background looked up", () => textureStore.PerformedLookups.Any());
}
// private void assertAnyBackground()
// {
// loadNextBackground();
// AddAssert("background looked up", () => textureStore.PerformedLookups.Any());
// }
private void assertNoBackgrounds()
{
AddAssert("no background available", () => backgroundLoader.LoadNextBackground() == null);
AddAssert("no lookups performed", () => !textureStore.PerformedLookups.Any());
}
// private void assertNoBackgrounds()
// {
// AddAssert("no background available", () => backgroundLoader.LoadNextBackground() == null);
// AddAssert("no lookups performed", () => !textureStore.PerformedLookups.Any());
// }
private class LookupLoggingTextureStore : LargeTextureStore
{
public List<string> PerformedLookups { get; } = new List<string>();
// private class LookupLoggingTextureStore : LargeTextureStore
// {
// public List<string> PerformedLookups { get; } = new List<string>();
public LookupLoggingTextureStore(IRenderer renderer)
: base(renderer)
{
}
// public LookupLoggingTextureStore(IRenderer renderer)
// : base(renderer)
// {
// }
public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT)
{
PerformedLookups.Add(name);
return base.Get(name, wrapModeS, wrapModeT);
}
}
}
}
// public override Texture Get(string name, WrapMode wrapModeS, WrapMode wrapModeT)
// {
// PerformedLookups.Add(name);
// return base.Get(name, wrapModeS, wrapModeT);
// }
// }
// }
// }

View File

@@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Beatmaps
AddStep("create thumbnail", () =>
{
var beatmapSet = CreateAPIBeatmapSet(Ruleset.Value);
beatmapSet.OnlineID = 241526; // ID hardcoded to ensure that the preview track exists online.
beatmapSet.OnlineID = 1; // ID hardcoded to ensure that the preview track exists online.
Child = thumbnail = new BeatmapCardThumbnail(beatmapSet, beatmapSet)
{

View File

@@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.Editing
setUpEditor(new OsuRuleset().RulesetInfo);
AddAssert("is osu! ruleset", () => editorBeatmap.BeatmapInfo.Ruleset.Equals(new OsuRuleset().RulesetInfo));
AddStep("jump to encoded link", () => Game.HandleLink("osu://edit/00:14:142%20(1)"));
AddStep("jump to encoded link", () => Game.HandleLink("jvnkosu://edit/00:14:142%20(1)"));
AddUntilStep("wait for seek", () => editorClock.SeekingOrStopped.Value);

View File

@@ -50,34 +50,6 @@ namespace osu.Game.Tests.Visual.Gameplay
sprites.All(sprite => sprite.ChildrenOfType<Sprite>().All(s => s.Texture == null)));
}
[Test]
public void TestSpriteFadeOverflowBehaviour()
{
AddStep("create sprite", () => SetContents(_ =>
{
var layer = storyboard.GetLayer("Background");
var sprite = new StoryboardSprite(lookup_name, Anchor.TopLeft, new Vector2(256, 192));
sprite.Commands.AddAlpha(Easing.None, Time.Current, Time.Current + 2000, 0, 2);
layer.Elements.Clear();
layer.Add(sprite);
return new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
storyboard.CreateDrawable()
}
};
}));
AddUntilStep("sprite reached high opacity once", () => sprites.All(sprite => sprite.ChildrenOfType<Sprite>().All(s => s.Alpha > 0.8f)));
AddUntilStep("sprite reset to low opacity", () => sprites.All(sprite => sprite.ChildrenOfType<Sprite>().All(s => s.Alpha < 0.2f)));
AddUntilStep("sprite reached high opacity twice", () => sprites.All(sprite => sprite.ChildrenOfType<Sprite>().All(s => s.Alpha > 0.8f)));
}
[Test]
public void TestLookupFromStoryboard()
{

View File

@@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counter = null!;
loadPlayer(() => new OsuRuleset());
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
checkKey(() => counter, 0, false);
AddStep("press Z", () => InputManager.PressKey(Key.Z));
@@ -117,7 +117,7 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counter = null!;
loadPlayer(() => new ManiaRuleset());
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<ManiaAction> actionTrigger && actionTrigger.Action == ManiaAction.Key4));
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<ManiaAction> actionTrigger && actionTrigger.Action == ManiaAction.Key4));
checkKey(() => counter, 0, false);
AddStep("press space", () => InputManager.PressKey(Key.Space));
@@ -150,8 +150,8 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counterX = null!;
loadPlayer(() => new OsuRuleset());
AddStep("get key counter Z", () => counterZ = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter X", () => counterX = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.RightButton));
AddStep("get key counter Z", () => counterZ = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter X", () => counterX = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.RightButton));
AddStep("press Z", () => InputManager.PressKey(Key.Z));
AddStep("pause", () => Player.Pause());
@@ -184,7 +184,7 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counter = null!;
loadPlayer(() => new ManiaRuleset());
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<ManiaAction> actionTrigger && actionTrigger.Action == ManiaAction.Key4));
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<ManiaAction> actionTrigger && actionTrigger.Action == ManiaAction.Key4));
AddStep("press space", () => InputManager.PressKey(Key.Space));
AddStep("pause", () => Player.Pause());
@@ -204,8 +204,8 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counterX = null!;
loadPlayer(() => new OsuRuleset());
AddStep("get key counter Z", () => counterZ = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter X", () => counterX = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.RightButton));
AddStep("get key counter Z", () => counterZ = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter X", () => counterX = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.RightButton));
AddStep("press Z", () => InputManager.PressKey(Key.Z));
AddStep("pause", () => Player.Pause());
@@ -247,7 +247,7 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counter = null!;
loadPlayer(() => new ManiaRuleset());
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<ManiaAction> actionTrigger && actionTrigger.Action == ManiaAction.Key4));
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<ManiaAction> actionTrigger && actionTrigger.Action == ManiaAction.Key4));
AddStep("press space", () => InputManager.PressKey(Key.Space));
checkKey(() => counter, 1, true);
@@ -271,7 +271,7 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counter = null!;
loadPlayer(() => new OsuRuleset());
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("pause", () => Player.Pause());
AddStep("resume", () => Player.Resume());
@@ -297,7 +297,7 @@ namespace osu.Game.Tests.Visual.Gameplay
KeyCounter counter = null!;
loadPlayer(() => new OsuRuleset());
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterActionTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("get key counter", () => counter = this.ChildrenOfType<KeyCounter>().Single(k => k.Trigger is KeyCounterBindingTrigger<OsuAction> actionTrigger && actionTrigger.Action == OsuAction.LeftButton));
AddStep("press Z", () => InputManager.PressKey(Key.Z));
AddAssert("circle hit", () => Player.ScoreProcessor.HighestCombo.Value, () => Is.EqualTo(1));

View File

@@ -18,7 +18,6 @@ using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD;
using osu.Game.Skinning;
using osu.Game.Skinning.Triangles;
using osu.Game.Tests.Gameplay;
@@ -36,7 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override Drawable CreateDefaultImplementation() => new TrianglesPerformancePointsCounter();
protected override Drawable CreateArgonImplementation() => new ArgonPerformancePointsCounter();
protected override Drawable CreateLegacyImplementation() => new LegacyPerformancePointsCounter();
protected override Drawable CreateLegacyImplementation() => Empty();
private Bindable<JudgementResult> lastJudgementResult => (Bindable<JudgementResult>)gameplayState.LastJudgementResult;

View File

@@ -642,7 +642,7 @@ namespace osu.Game.Tests.Visual.Gameplay
[BackgroundDependencyLoader]
private void load()
{
if (!AllowLoad.Wait(TimeSpan.FromSeconds(10)))
if (!AllowLoad.Wait(TimeSpan.FromSeconds(30)))
throw new TimeoutException();
}
}

View File

@@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
@@ -379,23 +378,6 @@ namespace osu.Game.Tests.Visual.Gameplay
() => Is.EqualTo(3));
}
[Test]
public void TestCopyPasteIdempotency()
{
string state = null!;
AddStep("select everything", () => InputManager.Keys(PlatformAction.SelectAll));
AddStep("dump state", () =>
{
state = JsonConvert.SerializeObject(skinEditor.SelectedComponents.Cast<Drawable>().Select(s => s.CreateSerialisedInfo()).ToArray());
});
AddStep("copy", () => InputManager.Keys(PlatformAction.Copy));
AddStep("delete", () => InputManager.Keys(PlatformAction.Delete));
AddStep("paste", () => InputManager.Keys(PlatformAction.Paste));
AddAssert("pasted state equals dumped",
() => JsonConvert.SerializeObject(skinEditor.SelectedComponents.Cast<Drawable>().Select(s => s.CreateSerialisedInfo()).ToArray()),
() => Is.EqualTo(state));
}
private SkinnableContainer globalHUDTarget => Player.ChildrenOfType<SkinnableContainer>()
.Single(c => c.Lookup.Lookup == GlobalSkinnableContainers.MainHUDComponents && c.Lookup.Ruleset == null);

View File

@@ -0,0 +1,29 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Screens.Menu;
namespace osu.Game.Tests.Visual.Menus
{
public partial class TestSceneDisclaimer : ScreenTestScene
{
[BackgroundDependencyLoader]
private void load()
{
AddStep("load disclaimer", () => LoadScreen(new Disclaimer()));
AddStep("toggle support", () =>
{
((DummyAPIAccess)API).LocalUser.Value = new APIUser
{
Username = API.LocalUser.Value.Username,
Id = API.LocalUser.Value.Id + 1,
IsSupporter = !API.LocalUser.Value.IsSupporter,
};
});
}
}
}

View File

@@ -159,7 +159,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("check request received", () =>
{
multiplayerClient.Verify(m => m.SendMatchRequest(It.Is<StartMatchCountdownRequest>(req =>
req.Duration == TimeSpan.FromSeconds(10)
req.Duration == TimeSpan.FromSeconds(30)
)), Times.Once);
});
}
@@ -181,7 +181,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("check request received", () =>
{
multiplayerClient.Verify(m => m.SendMatchRequest(It.Is<StartMatchCountdownRequest>(req =>
req.Duration == TimeSpan.FromSeconds(10)
req.Duration == TimeSpan.FromSeconds(30)
)), Times.Once);
});

View File

@@ -305,6 +305,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 2.0 } }),
new APIMod(new OsuModStrictTracking()),
new APIMod(new OsuModAutoplay()), // THIS IS PURELY TO ENABLE UNRANKED BADGE AND LET TEST PASS
// I AM NOT PROUD OF THIS
},
AllowedMods = new[]
{

View File

@@ -387,7 +387,7 @@ namespace osu.Game.Tests.Visual.Navigation
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
// Importantly, this occurs before base.load().
if (!loader.AllowLoad.Wait(TimeSpan.FromSeconds(10)))
if (!loader.AllowLoad.Wait(TimeSpan.FromSeconds(30)))
throw new TimeoutException();
return base.CreateChildDependencies(parent);

View File

@@ -24,7 +24,6 @@ using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Graphics.Carousel;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.Notifications.WebSocket;
@@ -34,7 +33,6 @@ using osu.Game.Overlays.BeatmapListing;
using osu.Game.Overlays.Mods;
using osu.Game.Overlays.Notifications;
using osu.Game.Overlays.Toolbar;
using osu.Game.Overlays.Volume;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mania.Configuration;
@@ -922,8 +920,12 @@ namespace osu.Game.Tests.Visual.Navigation
}
[Test]
[Explicit("Featured Artist dialog is never displayed as the filter is disabled by default.")]
public void TestFeaturedArtistDisclaimerDialog()
{
// NO-OP: FA dialog is not displayed ever
/*
BeatmapListingOverlay getBeatmapListingOverlay() => Game.ChildrenOfType<BeatmapListingOverlay>().FirstOrDefault();
AddStep("Wait for notifications to load", () => Game.SearchBeatmapSet(string.Empty));
@@ -941,6 +943,7 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("dialog dismissed", () => Game.ChildrenOfType<DialogOverlay>().Single().CurrentDialog == null);
AddUntilStep("featured artist filter is off", () => !getBeatmapListingOverlay().ChildrenOfType<BeatmapSearchGeneralFilterRow>().First().Current.Contains(SearchGeneral.FeaturedArtists));
*/
}
[Test]
@@ -1333,34 +1336,6 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("still nothing selected", () => Game.Beatmap.IsDefault);
}
[Test]
public void TestVolumeMeterDragDoesNotDismissFocusedOverlay()
{
AddStep("show beatmap overlay", () => Game.ShowBeatmapSet(1));
AddUntilStep("beatmap overlay still visible",
() => Game.ChildrenOfType<BeatmapSetOverlay>().SingleOrDefault()?.State.Value,
() => Is.EqualTo(Visibility.Visible));
AddStep("set game volume to max", () => Game.Dependencies.Get<FrameworkConfigManager>().SetValue(FrameworkSetting.VolumeUniversal, 1d));
AddStep("move to centre", () => InputManager.MoveMouseTo(Game));
AddStep("alt-scroll down", () =>
{
InputManager.PressKey(Key.AltLeft);
InputManager.ScrollVerticalBy(-1);
InputManager.ReleaseKey(Key.AltLeft);
});
AddUntilStep("wait for volume overlay to show", () => Game.ChildrenOfType<VolumeOverlay>().SingleOrDefault()?.State.Value, () => Is.EqualTo(Visibility.Visible));
AddStep("start dragging meter", () =>
{
InputManager.MoveMouseTo(Game.ChildrenOfType<VolumeMeter>().First().ChildrenOfType<OsuSpriteText>().First());
InputManager.PressButton(MouseButton.Left);
});
AddStep("drag away", () => InputManager.MoveMouseTo(Game.ChildrenOfType<VolumeMeter>().First().ChildrenOfType<OsuSpriteText>().First(), new Vector2(0, -100)));
AddStep("release mouse", () => InputManager.ReleaseButton(MouseButton.Left));
AddAssert("beatmap overlay still visible",
() => Game.ChildrenOfType<BeatmapSetOverlay>().SingleOrDefault()?.State.Value,
() => Is.EqualTo(Visibility.Visible));
}
private Func<Player> playToResults()
{
var player = playToCompletion();

View File

@@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Navigation
private const int requested_beatmap_id = 75;
private const int requested_beatmap_set_id = 1;
protected override TestOsuGame CreateTestGame() => new TestOsuGame(LocalStorage, API, new[] { $"osu://b/{requested_beatmap_id}" });
protected override TestOsuGame CreateTestGame() => new TestOsuGame(LocalStorage, API, new[] { $"jvnkosu://b/{requested_beatmap_id}" });
[SetUp]
public void Setup() => Schedule(() =>

View File

@@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Navigation
{
private const int requested_beatmap_set_id = 1;
protected override TestOsuGame CreateTestGame() => new TestOsuGame(LocalStorage, API, new[] { $"osu://s/{requested_beatmap_set_id}" });
protected override TestOsuGame CreateTestGame() => new TestOsuGame(LocalStorage, API, new[] { $"jvnkosu://s/{requested_beatmap_set_id}" });
[SetUp]
public void Setup() => Schedule(() =>

View File

@@ -84,9 +84,9 @@ namespace osu.Game.Tests.Visual.Online
public void TestFeaturedArtistFilter()
{
AddAssert("is visible", () => overlay.State.Value == Visibility.Visible);
AddAssert("featured artist filter is on", () => overlay.ChildrenOfType<BeatmapSearchGeneralFilterRow>().First().Current.Contains(SearchGeneral.FeaturedArtists));
AddStep("toggle featured artist filter", () => overlay.ChildrenOfType<FilterTabItem<SearchGeneral>>().First(i => i.Value == SearchGeneral.FeaturedArtists).TriggerClick());
AddAssert("featured artist filter is off", () => !overlay.ChildrenOfType<BeatmapSearchGeneralFilterRow>().First().Current.Contains(SearchGeneral.FeaturedArtists));
AddStep("toggle featured artist filter", () => overlay.ChildrenOfType<FilterTabItem<SearchGeneral>>().First(i => i.Value == SearchGeneral.FeaturedArtists).TriggerClick());
AddAssert("featured artist filter is on", () => overlay.ChildrenOfType<BeatmapSearchGeneralFilterRow>().First().Current.Contains(SearchGeneral.FeaturedArtists));
}
[Test]

View File

@@ -55,31 +55,31 @@ namespace osu.Game.Tests.Visual.Online
});
[TestCase("test!")]
[TestCase("dev.ppy.sh!")]
[TestCase("https://dev.ppy.sh!", LinkAction.External)]
[TestCase("http://dev.ppy.sh!", LinkAction.External)]
[TestCase("forgothttps://dev.ppy.sh!", LinkAction.External)]
[TestCase("forgothttp://dev.ppy.sh!", LinkAction.External)]
[TestCase("osu.jvnko.boats!")]
[TestCase("https://osu.jvnko.boats!", LinkAction.External)]
[TestCase("http://osu.jvnko.boats!", LinkAction.External)]
[TestCase("forgothttps://osu.jvnko.boats!", LinkAction.External)]
[TestCase("forgothttp://osu.jvnko.boats!", LinkAction.External)]
[TestCase("00:12:345 - Test?", LinkAction.OpenEditorTimestamp)]
[TestCase("00:12:345 (1,2) - Test?", LinkAction.OpenEditorTimestamp)]
[TestCase($"{OsuGameBase.OSU_PROTOCOL}edit/00:12:345 - Test?", LinkAction.OpenEditorTimestamp)]
[TestCase($"{OsuGameBase.OSU_PROTOCOL}edit/00:12:345 (1,2) - Test?", LinkAction.OpenEditorTimestamp)]
[TestCase($"{OsuGameBase.OSU_PROTOCOL}00:12:345 - not an editor timestamp", LinkAction.External)]
[TestCase("Wiki link for tasty [[Performance Points]]", LinkAction.OpenWiki)]
[TestCase("(osu forums)[https://dev.ppy.sh/forum] (old link format)", LinkAction.External)]
[TestCase("[https://dev.ppy.sh/home New site] (new link format)", LinkAction.External)]
[TestCase("[osu forums](https://dev.ppy.sh/forum) (new link format 2)", LinkAction.External)]
[TestCase("[https://dev.ppy.sh/home This is only a link to the new osu webpage but this is supposed to test word wrap.]", LinkAction.External)]
[TestCase("Let's (try)[https://dev.ppy.sh/home] [https://dev.ppy.sh/b/252238 multiple links] https://dev.ppy.sh/home", LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External)]
[TestCase("[https://dev.ppy.sh/home New link format with escaped [and \\[ paired] braces]", LinkAction.External)]
[TestCase("[Markdown link format with escaped [and \\[ paired] braces](https://dev.ppy.sh/home)", LinkAction.External)]
[TestCase("(Old link format with escaped (and \\( paired) parentheses)[https://dev.ppy.sh/home] and [[also a rogue wiki link]]", LinkAction.External, LinkAction.OpenWiki)]
[TestCase("(osu forums)[https://osu.jvnko.boats/forum] (old link format)", LinkAction.External)]
[TestCase("[https://osu.jvnko.boats/home New site] (new link format)", LinkAction.External)]
[TestCase("[osu forums](https://osu.jvnko.boats/forum) (new link format 2)", LinkAction.External)]
[TestCase("[https://osu.jvnko.boats/home This is only a link to the new osu webpage but this is supposed to test word wrap.]", LinkAction.External)]
[TestCase("Let's (try)[https://osu.jvnko.boats/home] [https://osu.jvnko.boats/b/252238 multiple links] https://osu.jvnko.boats/home", LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External)]
[TestCase("[https://osu.jvnko.boats/home New link format with escaped [and \\[ paired] braces]", LinkAction.External)]
[TestCase("[Markdown link format with escaped [and \\[ paired] braces](https://osu.jvnko.boats/home)", LinkAction.External)]
[TestCase("(Old link format with escaped (and \\( paired) parentheses)[https://osu.jvnko.boats/home] and [[also a rogue wiki link]]", LinkAction.External, LinkAction.OpenWiki)]
[TestCase("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).")] // note that there's 0 links here (they get removed if a channel is not found)
[TestCase("Join my multiplayer game osu://room/12346.", LinkAction.JoinRoom)]
[TestCase("Join my multiplayer gameosu://room/12346.", LinkAction.JoinRoom)]
[TestCase("Join my [multiplayer game](osu://room/12346).", LinkAction.JoinRoom)]
[TestCase("Join my multiplayer game http://dev.ppy.sh/multiplayer/rooms/12346", LinkAction.JoinRoom)]
[TestCase("Join my [multiplayer game](http://dev.ppy.sh/multiplayer/rooms/12346).", LinkAction.JoinRoom)]
[TestCase("Join my multiplayer game jvnkosu://room/12346.", LinkAction.JoinRoom)]
[TestCase("Join my multiplayer gamejvnkosu://room/12346.", LinkAction.JoinRoom)]
[TestCase("Join my [multiplayer game](jvnkosu://room/12346).", LinkAction.JoinRoom)]
[TestCase("Join my multiplayer game http://osu.jvnko.boats/multiplayer/rooms/12346", LinkAction.JoinRoom)]
[TestCase("Join my [multiplayer game](http://osu.jvnko.boats/multiplayer/rooms/12346).", LinkAction.JoinRoom)]
[TestCase($"Join my [#english]({OsuGameBase.OSU_PROTOCOL}chan/#english).", LinkAction.OpenChannel)]
[TestCase($"Join my {OsuGameBase.OSU_PROTOCOL}chan/#english.", LinkAction.OpenChannel)]
[TestCase($"Join my{OsuGameBase.OSU_PROTOCOL}chan/#english.", LinkAction.OpenChannel)]
@@ -91,11 +91,11 @@ namespace osu.Game.Tests.Visual.Online
addMessageWithChecks(text, expectedActions: actions);
}
[TestCase("is now listening to [https://dev.ppy.sh/s/93523 IMAGE -MATERIAL- <Version 0>]", true, false, LinkAction.OpenBeatmapSet)]
[TestCase("is now playing [https://dev.ppy.sh/b/252238 IMAGE -MATERIAL- <Version 0>]", true, false, LinkAction.OpenBeatmap)]
[TestCase("is now listening to [https://osu.jvnko.boats/s/93523 IMAGE -MATERIAL- <Version 0>]", true, false, LinkAction.OpenBeatmapSet)]
[TestCase("is now playing [https://osu.jvnko.boats/b/252238 IMAGE -MATERIAL- <Version 0>]", true, false, LinkAction.OpenBeatmap)]
[TestCase("I am important!", false, true)]
[TestCase("feels important", true, true)]
[TestCase("likes to post this [https://dev.ppy.sh/home link].", true, true, LinkAction.External)]
[TestCase("likes to post this [https://osu.jvnko.boats/home link].", true, true, LinkAction.External)]
public void TestActionAndImportantLinks(string text, bool isAction, bool isImportant, params LinkAction[] expectedActions)
{
addMessageWithChecks(text, isAction, isImportant, expectedActions);
@@ -135,9 +135,9 @@ namespace osu.Game.Tests.Visual.Online
int messageIndex = 0;
addEchoWithWait("sent!", "received!");
addEchoWithWait("https://dev.ppy.sh/home", null, 500);
addEchoWithWait("[https://dev.ppy.sh/forum let's try multiple words too!]");
addEchoWithWait("(long loading times! clickable while loading?)[https://dev.ppy.sh/home]", null, 5000);
addEchoWithWait("https://osu.jvnko.boats/home", null, 500);
addEchoWithWait("[https://osu.jvnko.boats/forum let's try multiple words too!]");
addEchoWithWait("(long loading times! clickable while loading?)[https://osu.jvnko.boats/home]", null, 5000);
void addEchoWithWait(string text, string? completeText = null, double delay = 250)
{

View File

@@ -93,7 +93,7 @@ namespace osu.Game.Tests.Visual.Ranking
AddStep("show example score", () =>
{
var score = TestResources.CreateTestScoreInfo(createTestBeatmap(new RealmUser()));
score.Mods = score.Mods.Append(new OsuModDifficultyAdjust()).ToArray();
score.Mods = score.Mods.Append(new OsuModAutoplay()).ToArray();
showPanel(score);
});

View File

@@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void testInfoLabels(int expectedCount)
{
AddAssert("check info labels exists", () => infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Any());
AddAssert("check info labels count", () => infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Count() == expectedCount);
AddAssert("check info labels count", () => infoWedge.Info.ChildrenOfType<BeatmapInfoWedge.WedgeInfoText.InfoLabel>().Count() >= expectedCount);
}
[SetUpSteps]

View File

@@ -214,7 +214,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
assertGroup(results, 3, "Pending", pendingBeatmap.Beatmaps, ref total);
assertGroup(results, 4, "Graveyard", graveyardBeatmap.Beatmaps, ref total);
assertGroup(results, 5, "Local", localBeatmap.Beatmaps, ref total);
assertGroup(results, 6, "Unknown", noneBeatmap.Beatmaps, ref total);
assertGroup(results, 6, "Offline", noneBeatmap.Beatmaps, ref total);
assertGroup(results, 7, "Loved", lovedBeatmap.Beatmaps, ref total);
assertTotal(results, total);
}

View File

@@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
[Test]
public void TestUnrankedBadge()
{
AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModDeflate() }));
AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModAutoplay() }));
AddUntilStep("Unranked badge shown", () => footerButtonMods.ChildrenOfType<FooterButtonMods.UnrankedBadge>().Single().Alpha == 1);
AddStep(@"Clear selected mod", () => changeMods(Array.Empty<Mod>()));
AddUntilStep("Unranked badge not shown", () => footerButtonMods.ChildrenOfType<FooterButtonMods.UnrankedBadge>().Single().Alpha == 0);

View File

@@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.UserInterface
[Test]
public void TestUnrankedBadge()
{
AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModDeflate() }));
AddStep(@"Add unranked mod", () => changeMods(new[] { new OsuModAutoplay() }));
AddAssert("Unranked badge shown", () => footerButtonMods.UnrankedBadge.Alpha == 1);
AddStep(@"Clear selected mod", () => changeMods(Array.Empty<Mod>()));
AddAssert("Unranked badge not shown", () => footerButtonMods.UnrankedBadge.Alpha == 0);

View File

@@ -129,8 +129,9 @@ namespace osu.Game.Tests.Visual.UserInterface
setSliderValue("Circle Size", 99);
checkSliderAtValue("Circle Size", 11);
checkBindableAtValue("Circle Size", 11);
// debug build maximum value
checkSliderAtValue("Circle Size", 13);
checkBindableAtValue("Circle Size", 13);
setSliderValue("Approach Rate", -5);

View File

@@ -207,23 +207,23 @@ namespace osu.Game.Tests.Visual.UserInterface
AddUntilStep("any column dimmed", () => this.ChildrenOfType<ModColumn>().Any(column => !column.Active.Value));
ModSelectColumn lastColumn = null!;
ModSelectColumn secondColumn = null!;
AddAssert("last column dimmed", () => !this.ChildrenOfType<ModColumn>().Last().Active.Value);
AddStep("request scroll to last column", () =>
AddAssert("second column dimmed", () => !this.ChildrenOfType<ModColumn>().ElementAt(2).Active.Value);
AddStep("request scroll to second column", () =>
{
var lastDimContainer = this.ChildrenOfType<ModSelectOverlay.ColumnDimContainer>().Last();
lastColumn = lastDimContainer.Column;
lastDimContainer.RequestScroll?.Invoke(lastDimContainer);
var secondDimContainer = this.ChildrenOfType<ModSelectOverlay.ColumnDimContainer>().ElementAt(2);
secondColumn = secondDimContainer.Column;
secondDimContainer.RequestScroll?.Invoke(secondDimContainer);
});
AddUntilStep("column undimmed", () => lastColumn.Active.Value);
AddUntilStep("column undimmed", () => secondColumn.Active.Value);
AddStep("click panel", () =>
{
InputManager.MoveMouseTo(lastColumn.ChildrenOfType<ModPanel>().First());
InputManager.MoveMouseTo(secondColumn.ChildrenOfType<ModPanel>().First());
InputManager.Click(MouseButton.Left);
});
AddUntilStep("panel selected", () => lastColumn.ChildrenOfType<ModPanel>().First().Active.Value);
AddUntilStep("panel selected", () => secondColumn.ChildrenOfType<ModPanel>().First().Active.Value);
}
[Test]
@@ -810,7 +810,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("two columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 2);
AddStep("unset filter", () => modSelectOverlay.IsValidMod = _ => true);
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 4);
AddStep("filter out everything", () => modSelectOverlay.IsValidMod = _ => false);
AddAssert("no columns visible", () => this.ChildrenOfType<ModColumn>().All(col => !col.IsPresent));
@@ -839,7 +839,7 @@ namespace osu.Game.Tests.Visual.UserInterface
waitForColumnLoad();
changeRuleset(0);
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 4);
AddStep("set search", () => modSelectOverlay.SearchTerm = "HD");
AddAssert("two columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 2);
@@ -848,7 +848,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("no columns visible", () => this.ChildrenOfType<ModColumn>().All(col => !col.IsPresent));
AddStep("clear search bar", () => modSelectOverlay.SearchTerm = "");
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 4);
}
[Test]
@@ -863,7 +863,7 @@ namespace osu.Game.Tests.Visual.UserInterface
waitForColumnLoad();
changeRuleset(0);
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 4);
AddStep("set search", () => modSelectOverlay.SearchTerm = "fail");
AddAssert("one column visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 1);
@@ -871,7 +871,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("hide", () => modSelectOverlay.Hide());
AddStep("show", () => modSelectOverlay.Show());
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().All(col => col.IsPresent));
AddAssert("all columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 4);
}
[Test]
@@ -880,13 +880,13 @@ namespace osu.Game.Tests.Visual.UserInterface
createScreen();
changeRuleset(0);
AddAssert("5 columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 5);
AddAssert("5 or more columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 5);
AddStep("change to ruleset without all mod types", () => Ruleset.Value = TestCustomisableModRuleset.CreateTestRulesetInfo());
AddUntilStep("1 column visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 1);
changeRuleset(0);
AddAssert("5 columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) == 5);
AddAssert("5 or more columns visible", () => this.ChildrenOfType<ModColumn>().Count(col => col.IsPresent) >= 5);
}
[Test]

View File

@@ -107,7 +107,7 @@ namespace osu.Game.Audio
Logger.Log($"A {nameof(PreviewTrack)} was created without a containing {nameof(IPreviewTrackOwner)}. An owner should be added for correct behaviour.");
}
protected override Track GetTrack() => trackManager.Get($"https://b.ppy.sh/preview/{beatmapSetInfo.OnlineID}.mp3");
protected override Track GetTrack() => trackManager.Get($"https://osu.jvnko.boats/uploads/preview/{beatmapSetInfo.OnlineID}.mp3");
}
}
}

View File

@@ -13,6 +13,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Beatmaps.Formats;
using osu.Game.Configuration;
using osu.Game.Collections;
using osu.Game.Database;
using osu.Game.Extensions;
@@ -36,8 +37,8 @@ namespace osu.Game.Beatmaps
public ProcessBeatmapDelegate? ProcessBeatmap { private get; set; }
public BeatmapImporter(Storage storage, RealmAccess realm)
: base(storage, realm)
public BeatmapImporter(Storage storage, RealmAccess realm, OsuConfigManager? config = null)
: base(storage, realm, config)
{
}

View File

@@ -17,6 +17,7 @@ using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Formats;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Extensions;
using osu.Game.IO.Archives;
@@ -59,7 +60,7 @@ namespace osu.Game.Beatmaps
}
public BeatmapManager(Storage storage, RealmAccess realm, IAPIProvider? api, AudioManager audioManager, IResourceStore<byte[]> gameResources, GameHost? host = null,
WorkingBeatmap? defaultBeatmap = null, BeatmapDifficultyCache? difficultyCache = null, bool performOnlineLookups = false)
WorkingBeatmap? defaultBeatmap = null, BeatmapDifficultyCache? difficultyCache = null, bool performOnlineLookups = false, OsuConfigManager? config = null)
: base(storage, realm)
{
if (performOnlineLookups)
@@ -75,7 +76,7 @@ namespace osu.Game.Beatmaps
BeatmapTrackStore = audioManager.GetTrackStore(userResources);
beatmapImporter = CreateBeatmapImporter(storage, realm);
beatmapImporter = CreateBeatmapImporter(storage, realm, config);
beatmapImporter.ProcessBeatmap = (beatmapSet, scope) => ProcessBeatmap?.Invoke(beatmapSet, scope);
beatmapImporter.PostNotification = obj => PostNotification?.Invoke(obj);
@@ -98,7 +99,7 @@ namespace osu.Game.Beatmaps
return new WorkingBeatmapCache(BeatmapTrackStore, audioManager, resources, storage, defaultBeatmap, host);
}
protected virtual BeatmapImporter CreateBeatmapImporter(Storage storage, RealmAccess realm) => new BeatmapImporter(storage, realm);
protected virtual BeatmapImporter CreateBeatmapImporter(Storage storage, RealmAccess realm, OsuConfigManager? config = null) => new BeatmapImporter(storage, realm, config);
/// <summary>
/// Create a new beatmap set, backed by a <see cref="BeatmapSetInfo"/> model,

View File

@@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps
LocallyModified = -4,
[LocalisableDescription(typeof(SongSelectStrings), nameof(SongSelectStrings.StatusUnknown))]
[Description("Unknown")]
[Description("Offline")]
None = -3,
[LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowStatusGraveyard))]

View File

@@ -33,7 +33,8 @@ namespace osu.Game.Beatmaps.Drawables.Cards
Status = beatmapSet.Status,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
TextSize = 13f
TextSize = 13f,
ShowUnknownStatus = true
},
new DifficultySpectrumDisplay
{

View File

@@ -8,6 +8,7 @@ namespace osu.Game.Configuration
Circles,
Welcome,
Triangles,
None,
Random
}
}

View File

@@ -8,6 +8,7 @@ using osu.Framework.Configuration;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Extensions;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Framework.Platform;
using osu.Game.Beatmaps.Drawables.Cards;
@@ -41,6 +42,8 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.Ruleset, string.Empty);
SetDefault(OsuSetting.Skin, SkinInfo.ARGON_SKIN.ToString());
SetDefault(OsuSetting.MenuCookieColor, Colour4.FromHex(@"8400FF"));
SetDefault(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Local);
SetDefault(OsuSetting.BeatmapLeaderboardSortMode, LeaderboardSortMode.Score);
SetDefault(OsuSetting.BeatmapDetailModsFilter, false);
@@ -59,12 +62,13 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2f, 1f, 0.01f);
SetDefault(OsuSetting.BeatmapListingCardSize, BeatmapCardSize.Normal);
SetDefault(OsuSetting.BeatmapListingFeaturedArtistFilter, true);
SetDefault(OsuSetting.BeatmapListingFeaturedArtistFilter, false);
SetDefault(OsuSetting.ProfileCoverExpanded, true);
SetDefault(OsuSetting.ToolbarClockDisplayMode, ToolbarClockDisplayMode.Full);
SetDefault(OsuSetting.ForceLegacySongSelect, false);
SetDefault(OsuSetting.SongSelectBackgroundBlur, false);
// Online settings
@@ -92,7 +96,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.ExternalLinkWarning, true);
SetDefault(OsuSetting.PreferNoVideo, false);
SetDefault(OsuSetting.BackgroundCategory, "Default");
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
SetDefault(OsuSetting.NotifyOnUsernameMentioned, true);
@@ -154,6 +158,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.ReplayPlaybackControlsExpanded, true);
SetDefault(OsuSetting.GameplayLeaderboard, true);
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
SetDefault(OsuSetting.AlwaysPlayComboBreak, false);
SetDefault(OsuSetting.FloatingComments, false);
@@ -193,10 +198,13 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.IntroSequence, IntroSequence.Triangles);
SetDefault(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
SetDefault(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes);
SetDefault(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Never);
SetDefault(OsuSetting.UseSeasonalBackgroundsV2, true);
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
SetDefault(OsuSetting.DeleteImportedArchives, true);
SetDefault(OsuSetting.EditorDim, 0.25f, 0f, 0.75f, 0.25f);
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f);
SetDefault(OsuSetting.EditorShowHitMarkers, true);
@@ -362,6 +370,7 @@ namespace osu.Game.Configuration
GameplayLeaderboard,
PositionalHitsoundsLevel,
AlwaysPlayFirstComboBreak,
AlwaysPlayComboBreak,
FloatingComments,
HUDVisibilityMode,
@@ -405,6 +414,7 @@ namespace osu.Game.Configuration
ChatDisplayHeight,
BeatmapListingCardSize,
ToolbarClockDisplayMode,
ForceLegacySongSelect,
SongSelectBackgroundBlur,
Version,
ShowFirstRunSetup,
@@ -412,6 +422,7 @@ namespace osu.Game.Configuration
Skin,
ScreenshotFormat,
ScreenshotCaptureMenuCursor,
MenuCookieColor,
BeatmapSkins,
BeatmapColours,
BeatmapHitsounds,
@@ -436,10 +447,13 @@ namespace osu.Game.Configuration
MenuBackgroundSource,
GameplayDisableWinKey,
SeasonalBackgroundMode,
UseSeasonalBackgroundsV2, // TODO: add migrations
BackgroundCategory,
EditorWaveformOpacity,
EditorShowHitMarkers,
EditorAutoSeekOnPlacement,
DiscordRichPresence,
DeleteImportedArchives,
ShowOnlineExplicitContent,
LastProcessedMetadataId,

View File

@@ -14,12 +14,6 @@ namespace osu.Game.Configuration
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.AlwaysSeasonalBackground))]
Always,
/// <summary>
/// Seasonal backgrounds are shown only during their corresponding season.
/// </summary>
[LocalisableDescription(typeof(UserInterfaceStrings), nameof(UserInterfaceStrings.SometimesSeasonalBackground))]
Sometimes,
/// <summary>
/// Seasonal backgrounds are never shown.
/// </summary>

View File

@@ -0,0 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Configuration
{
public enum WelcomeMusicMode
{
Default,
Custom
}
}

View File

@@ -206,11 +206,26 @@ namespace osu.Game.Database
if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal))
Filename += realm_extension;
// since I'm an idiot, I will have to suffer
#if DEBUG
if (!DebugUtils.IsNUnitRunning)
applyFilenameSchemaSuffix(ref Filename);
#endif
#if !DEBUG
// in the lazer. straight up "migrating it". and by "it", haha, well. let's just say. My realm .
string altFilename = filename;
applyFilenameSchemaSuffix(ref altFilename);
if (storage.Exists(altFilename) && !storage.Exists(Filename))
{
using (var previous = storage.GetStream(altFilename))
using (var current = storage.CreateFileSafely(Filename))
{
Logger.Log($@"Migrating production build DB: {altFilename} -> {Filename}");
previous.CopyTo(current);
Logger.Log("Sucessfully migrated local database!", level: LogLevel.Important);
}
}
#endif
// `prepareFirstRealmAccess()` triggers the first `getRealmInstance` call, which will implicitly run realm migrations and bring the schema up-to-date.
using (var realm = prepareFirstRealmAccess())
cleanupPendingDeletions(realm);

View File

@@ -8,11 +8,14 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.IO.Archives;
using osu.Game.Models;
@@ -77,11 +80,19 @@ namespace osu.Game.Database
/// </summary>
public Action<Notification>? PostNotification { get; set; }
protected RealmArchiveModelImporter(Storage storage, RealmAccess realm)
private readonly OsuConfigManager? config;
private Bindable<bool>? deleteImportedArchives;
protected RealmArchiveModelImporter(Storage storage, RealmAccess realm, OsuConfigManager? config = null)
{
Realm = realm;
Files = new RealmFileStore(realm, storage);
deleteImportedArchives = config?.GetBindable<bool>(OsuSetting.DeleteImportedArchives);
this.config = config;
}
public Task Import(params string[] paths) => Import(paths.Select(p => new ImportTask(p)).ToArray());
@@ -252,9 +263,10 @@ namespace osu.Game.Database
// e.g. reconstructing/repairing database with items from default storage.
// Also, not always a single file, i.e. for LegacyFilesystemReader
// TODO: Add a check to prevent files from storage to be deleted.
bool allowDelete = deleteImportedArchives?.Value ?? true;
try
{
if (import != null && ShouldDeleteArchive(task.Path))
if (import != null && ShouldDeleteArchive(task.Path) && allowDelete)
task.DeleteFile();
}
catch (Exception e)

View File

@@ -4,6 +4,7 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -19,79 +20,121 @@ namespace osu.Game.Graphics.Backgrounds
{
public partial class SeasonalBackgroundLoader : Component
{
public event Action<Exception> OnLoadFailure;
public event Action BackgroundChanged;
/// <summary>
/// Fired when background should be changed due to receiving backgrounds from API
/// or when the user setting is changed (as it might require unloading the seasonal background).
/// Fired when categories have been successfully refreshed from the server.
/// </summary>
public event Action SeasonalBackgroundChanged;
public event Action OnCategoriesRefreshed;
public readonly Bindable<IEnumerable<string>> AvailableCategories = new Bindable<IEnumerable<string>>(new List<string>());
[Resolved]
private IAPIProvider api { get; set; }
private Bindable<SeasonalBackgroundMode> seasonalBackgroundMode;
private Bindable<APISeasonalBackgrounds> seasonalBackgrounds;
private readonly IBindable<APIState> apiState = new Bindable<APIState>();
private Bindable<bool> useSeasonalBackgrounds;
private Bindable<string> selectedCategory;
private Bindable<APISeasonalBackgrounds> currentBackgrounds;
private int current;
private int currentBackgroundIndex;
private bool shouldShowCustomBackgrounds => useSeasonalBackgrounds.Value;
private bool shouldFetchCustomBackgrounds = false;
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, SessionStatics sessionStatics)
{
seasonalBackgroundMode = config.GetBindable<SeasonalBackgroundMode>(OsuSetting.SeasonalBackgroundMode);
seasonalBackgroundMode.BindValueChanged(_ => SeasonalBackgroundChanged?.Invoke());
useSeasonalBackgrounds = config.GetBindable<bool>(OsuSetting.UseSeasonalBackgroundsV2);
useSeasonalBackgrounds.BindValueChanged(_ => BackgroundChanged?.Invoke());
seasonalBackgrounds = sessionStatics.GetBindable<APISeasonalBackgrounds>(Static.SeasonalBackgrounds);
seasonalBackgrounds.BindValueChanged(_ =>
{
if (shouldShowSeasonal)
SeasonalBackgroundChanged?.Invoke();
});
selectedCategory = config.GetBindable<string>(OsuSetting.BackgroundCategory);
selectedCategory.BindValueChanged(_ => fetchBackgroundsForSelectedCategory());
fetchSeasonalBackgrounds();
currentBackgrounds = sessionStatics.GetBindable<APISeasonalBackgrounds>(Static.SeasonalBackgrounds);
if (shouldShowCustomBackgrounds)
fetchCategories(true);
apiState.BindTo(api.State);
apiState.BindValueChanged(d => shouldFetchCustomBackgrounds = d.NewValue == APIState.Online, true);
}
private void fetchSeasonalBackgrounds()
/// <summary>
/// Public method to trigger a refresh of categories from the UI.
/// </summary>
public void RefreshCategories(bool ignoreSuccess = false)
{
if (seasonalBackgrounds.Value != null)
return;
fetchCategories(ignoreSuccess);
}
private void fetchCategories(bool ignoreSuccess = false)
{
if (!shouldShowCustomBackgrounds) return;
var request = new GetBackgroundCategoriesRequest();
var request = new GetSeasonalBackgroundsRequest();
request.Success += response =>
{
seasonalBackgrounds.Value = response;
current = RNG.Next(0, response.Backgrounds?.Count ?? 0);
var serverCategories = response.Categories ?? Enumerable.Empty<string>();
AvailableCategories.Value = serverCategories.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
if (!AvailableCategories.Value.Any())
{
selectedCategory.Value = "";
return; // we don't have any categories!!!
}
if (!AvailableCategories.Value.Contains(selectedCategory.Value))
selectedCategory.Value = AvailableCategories.Value.Contains("Default")
? "Default"
: AvailableCategories.Value.ElementAt(0);
fetchBackgroundsForSelectedCategory();
if (!ignoreSuccess)
OnCategoriesRefreshed?.Invoke();
};
request.Failure += exception =>
{
AvailableCategories.Value = Array.Empty<string>();
OnLoadFailure?.Invoke(exception);
};
api.PerformAsync(request);
}
public SeasonalBackground LoadNextBackground()
private void fetchBackgroundsForSelectedCategory()
{
if (!shouldShowSeasonal)
return null;
if (!shouldShowCustomBackgrounds) return;
var backgrounds = seasonalBackgrounds.Value.Backgrounds;
string categoryToFetch = selectedCategory.Value == "Default" ? null : selectedCategory.Value;
var request = new GetSeasonalBackgroundsRequest(categoryToFetch);
current = (current + 1) % backgrounds.Count;
string url = backgrounds[current].Url;
request.Success += response =>
{
currentBackgrounds.Value = response;
currentBackgroundIndex = RNG.Next(0, response.Backgrounds?.Count ?? 0);
BackgroundChanged?.Invoke();
};
api.PerformAsync(request);
}
public Background LoadNextBackground()
{
if (!shouldShowCustomBackgrounds || !shouldFetchCustomBackgrounds || currentBackgrounds.Value?.Backgrounds?.Any() != true)
return new Background($@"Menu/menu-background-{RNG.Next(1, 9)}");
var backgrounds = currentBackgrounds.Value.Backgrounds;
currentBackgroundIndex = (currentBackgroundIndex + 1) % backgrounds.Count;
string url = backgrounds[currentBackgroundIndex].Url;
return new SeasonalBackground(url);
}
private bool shouldShowSeasonal
{
get
{
if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Never)
return false;
if (seasonalBackgroundMode.Value == SeasonalBackgroundMode.Sometimes && !isInSeason)
return false;
return seasonalBackgrounds.Value?.Backgrounds?.Any() == true;
}
}
private bool isInSeason => seasonalBackgrounds.Value != null && DateTimeOffset.Now < seasonalBackgrounds.Value.EndDate;
}
[LongRunningLoad]

View File

@@ -1,13 +1,11 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Layout;
using osu.Framework.Platform;
using osu.Framework.Screens;
@@ -52,8 +50,6 @@ namespace osu.Game.Graphics.Containers
private RectangleF? customRect;
private bool customRectIsRelativePosition;
private ITabletHandler? tabletHandler;
/// <summary>
/// Set a custom position and scale which overrides any user specification.
/// </summary>
@@ -127,7 +123,7 @@ namespace osu.Game.Graphics.Containers
}
[BackgroundDependencyLoader]
private void load(GameHost host, OsuConfigManager config, ISafeArea safeArea)
private void load(OsuConfigManager config, ISafeArea safeArea)
{
scalingMode = config.GetBindable<ScalingMode>(OsuSetting.Scaling);
scalingMode.ValueChanged += _ => Scheduler.AddOnce(updateSize);
@@ -152,8 +148,6 @@ namespace osu.Game.Graphics.Containers
scalingMenuBackgroundDim = config.GetBindable<float>(OsuSetting.ScalingBackgroundDim);
scalingMenuBackgroundDim.ValueChanged += _ => Scheduler.AddOnce(updateSize);
tabletHandler = host.AvailableInputHandlers.OfType<ITabletHandler>().SingleOrDefault();
}
protected override void LoadComplete()
@@ -228,13 +222,6 @@ namespace osu.Game.Graphics.Containers
// An example of how this can occur is when the skin editor is visible and the game screen scaling is set to "Everything".
sizableContainer.TransformTo(nameof(CornerRadius), requiresMasking ? corner_radius : 0, TRANSITION_DURATION, requiresMasking ? Easing.OutQuart : Easing.None)
.OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
// when "everything" scaling mode is active, tablets are expected to constrain output area to the scaled size of the game
if (tabletHandler != null)
{
tabletHandler.OutputAreaSize.Value = scalingMode.Value == ScalingMode.Everything ? new Vector2(sizeX.Value, sizeY.Value) : Vector2.One;
tabletHandler.OutputAreaOffset.Value = scalingMode.Value == ScalingMode.Everything ? new Vector2(posX.Value, posY.Value) : new Vector2(0.5f);
}
}
private partial class ScalingBackgroundScreen : BackgroundScreenDefault

View File

@@ -129,7 +129,7 @@ namespace osu.Game.Graphics
switch (status)
{
case BeatmapOnlineStatus.None:
return Color4.RosyBrown;
return Color4.AliceBlue;
case BeatmapOnlineStatus.LocallyModified:
return Color4.OrangeRed;
@@ -183,6 +183,9 @@ namespace osu.Game.Graphics
case ModType.System:
return Yellow;
case ModType.Special:
return Orange2;
default:
throw new ArgumentOutOfRangeException(nameof(modType), modType, "Unknown mod type");
}

View File

@@ -60,7 +60,7 @@ namespace osu.Game.Graphics.UserInterface
}
[Resolved]
protected OverlayColourProvider ColourProvider { get; private set; } = null!;
protected OverlayColourProvider? ColourProvider { get; private set; } = null!;
private readonly Box background;
private readonly OsuSpriteText text;
@@ -190,9 +190,9 @@ namespace osu.Game.Graphics.UserInterface
private void updateState()
{
var colourDark = darkerColour ?? ColourProvider.Background3;
var colourLight = lighterColour ?? ColourProvider.Background1;
var colourContent = textColour ?? ColourProvider.Content1;
var colourDark = darkerColour ?? ColourProvider?.Background3 ?? Colour4.DarkGray;
var colourLight = lighterColour ?? ColourProvider?.Background1 ?? Colour4.LightGray;
var colourContent = textColour ?? ColourProvider?.Content1 ?? Colour4.White;
if (!Enabled.Value)
{

View File

@@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
namespace osu.Game.Graphics.UserInterface
{
@@ -63,9 +64,9 @@ namespace osu.Game.Graphics.UserInterface
protected virtual void UpdateActiveState()
{
DarkerColour = Active.Value ? ColourProvider.Highlight1 : ColourProvider.Background3;
LighterColour = Active.Value ? ColourProvider.Colour0 : ColourProvider.Background1;
TextColour = Active.Value ? ColourProvider.Background6 : ColourProvider.Content1;
DarkerColour = Active.Value ? ColourProvider?.Highlight1 ?? Colour4.Gray : ColourProvider?.Background3 ?? Colour4.DimGray;
LighterColour = Active.Value ? ColourProvider?.Colour0 ?? Colour4.AliceBlue : ColourProvider?.Background1 ?? Colour4.LightGray;
TextColour = Active.Value ? ColourProvider?.Background6 ?? Colour4.Black : ColourProvider?.Content1 ?? Colour4.DarkGray;
}
private void playSample()

View File

@@ -140,9 +140,9 @@ namespace osu.Game.Localisation
public static LocalisableString LoadInBrowserAfterSubmission => new TranslatableString(getKey(@"load_in_browser_after_submission"), @"Load in browser after submission");
/// <summary>
/// "Note: In order to make it possible for users of all osu! versions to enjoy your beatmap, it will be exported in a backwards-compatible format. While we have made efforts to ensure that this process keeps the beatmap playable in its intended form, some data related to features that previous versions of osu! do not support may be lost."
/// "Note: In order to make it possible for users of all game versions to enjoy your beatmap, it will be exported in a backwards-compatible format. While we have made efforts to ensure that this process keeps the beatmap playable in its intended form, some data related to features that previous versions of osu! do not support may be lost."
/// </summary>
public static LocalisableString LegacyExportDisclaimer => new TranslatableString(getKey(@"legacy_export_disclaimer"), @"Note: In order to make it possible for users of all osu! versions to enjoy your beatmap, it will be exported in a backwards-compatible format. While we have made efforts to ensure that this process keeps the beatmap playable in its intended form, some data related to features that previous versions of osu! do not support may be lost.");
public static LocalisableString LegacyExportDisclaimer => new TranslatableString(getKey(@"legacy_export_disclaimer"), @"Note: In order to make it possible for users of all game versions to enjoy your beatmap, it will be exported in a backwards-compatible format. While we have made efforts to ensure that this process keeps the beatmap playable in its intended form, some data related to features that previous versions of osu! do not support may be lost.");
/// <summary>
/// "Empty beatmaps cannot be submitted."

View File

@@ -78,6 +78,23 @@ Your experience will not be perfect, and may even feel subpar compared to games
Please bear with us as we continue to improve the game for you!");
/// <summary>
/// "Welcome to jvnkosu!"
/// </summary>
public static LocalisableString GreetingNotification => new TranslatableString(getKey(@"greeting_notification"), @"Welcome to jvnkosu!");
/// <summary>
/// "Failed to load backgrounds!
/// Please check your internet connection"
/// </summary>
public static LocalisableString SeasonalBackgroundsFail => new TranslatableString(getKey(@"seasonal_backgrounds_fail"),
@"Failed to load backgrounds!
Please check your internet connection"); // TODO: implement l10n in osu-resources
/// <summary>
/// "Successfully refreshed background categories!"
/// </summary>
public static LocalisableString SeasonalBackgroundsRefreshed => new TranslatableString(getKey(@"seasonal_backgrounds_refreshed"), @"Successfully refreshed background categories!");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@@ -65,14 +65,14 @@ namespace osu.Game.Localisation
public static LocalisableString LightweightLinkingNotSupported => new TranslatableString(getKey(@"lightweight_linking_not_supported"), @"Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import.");
/// <summary>
/// "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS)."
/// "A second copy of all files will be made during import. To avoid this, please make sure this game's data folder is on the same drive as your previous osu! install (and the file system is NTFS)."
/// </summary>
public static LocalisableString SecondCopyWillBeMadeWindows => new TranslatableString(getKey(@"second_copy_will_be_made_windows"), @"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS).");
public static LocalisableString SecondCopyWillBeMadeWindows => new TranslatableString(getKey(@"second_copy_will_be_made_windows"), @"A second copy of all files will be made during import. To avoid this, please make sure this game's data folder is on the same drive as your previous osu! install (and the file system is NTFS).");
/// <summary>
/// "A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system supports hard links)."
/// "A second copy of all files will be made during import. To avoid this, please make sure this game's data folder is on the same drive as your previous osu! install (and the file system supports hard links)."
/// </summary>
public static LocalisableString SecondCopyWillBeMadeOtherPlatforms => new TranslatableString(getKey(@"second_copy_will_be_made_other_platforms"), @"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system supports hard links).");
public static LocalisableString SecondCopyWillBeMadeOtherPlatforms => new TranslatableString(getKey(@"second_copy_will_be_made_other_platforms"), @"A second copy of all files will be made during import. To avoid this, please make sure this game's data folder is on the same drive as your previous osu! install (and the file system supports hard links).");
private static string getKey(string key) => $@"{prefix}:{key}";
}

View File

@@ -15,9 +15,9 @@ namespace osu.Game.Localisation
public static LocalisableString Header => new TranslatableString(getKey(@"header"), @"Obtaining Beatmaps");
/// <summary>
/// "&quot;Beatmaps&quot; are what we call sets of playable levels. osu! doesn&#39;t come with any beatmaps pre-loaded. This step will help you get started on your beatmap collection."
/// "&quot;Beatmaps&quot; are what we call sets of playable levels. Game doesn&#39;t come with any beatmaps pre-loaded. This step will help you get started on your beatmap collection."
/// </summary>
public static LocalisableString Description => new TranslatableString(getKey(@"description"), @"""Beatmaps"" are what we call sets of playable levels. osu! doesn't come with any beatmaps pre-loaded. This step will help you get started on your beatmap collection.");
public static LocalisableString Description => new TranslatableString(getKey(@"description"), @"""Beatmaps"" are what we call sets of playable levels. Game doesn't come with any beatmaps pre-loaded. This step will help you get started on your beatmap collection.");
/// <summary>
/// "If you are a new player, we recommend playing through the tutorial to get accustomed to the gameplay."
@@ -25,9 +25,9 @@ namespace osu.Game.Localisation
public static LocalisableString TutorialDescription => new TranslatableString(getKey(@"tutorial_description"), @"If you are a new player, we recommend playing through the tutorial to get accustomed to the gameplay.");
/// <summary>
/// "Get the osu! tutorial"
/// "Get the tutorial"
/// </summary>
public static LocalisableString TutorialButton => new TranslatableString(getKey(@"tutorial_button"), @"Get the osu! tutorial");
public static LocalisableString TutorialButton => new TranslatableString(getKey(@"tutorial_button"), @"Get the tutorial");
/// <summary>
/// "To get you started, we have some recommended beatmaps."

Some files were not shown because too many files have changed in this diff Show More