diff --git a/.editorconfig b/.editorconfig
index 8cdb92d11c..67f98f94eb 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -135,7 +135,7 @@ csharp_preferred_modifier_order = public,private,protected,internal,new,abstract
csharp_style_expression_bodied_accessors = true:warning
csharp_style_expression_bodied_constructors = false:none
csharp_style_expression_bodied_indexers = true:warning
-csharp_style_expression_bodied_methods = true:silent
+csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_operators = true:warning
csharp_style_expression_bodied_properties = true:warning
csharp_style_expression_bodied_local_functions = true:silent
diff --git a/.gitignore b/.gitignore
index e6b5db5904..732b171f69 100644
--- a/.gitignore
+++ b/.gitignore
@@ -331,3 +331,6 @@ fastlane/report.xml
# inspectcode
inspectcodereport.xml
inspectcode
+
+# BenchmarkDotNet
+/BenchmarkDotNet.Artifacts
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml
new file mode 100644
index 0000000000..1815c271b4
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml
new file mode 100644
index 0000000000..d85a0ae44c
--- /dev/null
+++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/osu_SDL.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
index e7b691909e..6480612b2e 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,6 +1,7 @@
{
"version": "0.2.0",
- "configurations": [{
+ "configurations": [
+ {
"name": "osu! (Debug)",
"type": "coreclr",
"request": "launch",
@@ -50,7 +51,8 @@
}
},
"console": "internalConsole"
- }, {
+ },
+ {
"name": "osu! (Tests, Release)",
"type": "coreclr",
"request": "launch",
@@ -139,6 +141,19 @@
},
"console": "internalConsole"
},
+ {
+ "name": "Benchmark",
+ "type": "coreclr",
+ "request": "launch",
+ "program": "${workspaceRoot}/osu.Game.Benchmarks/bin/Release/netcoreapp3.1/osu.Game.Benchmarks.dll",
+ "args": [
+ "--filter",
+ "*"
+ ],
+ "cwd": "${workspaceRoot}",
+ "preLaunchTask": "Build benchmarks",
+ "console": "internalConsole"
+ },
{
"name": "Cake: Debug Script",
"type": "coreclr",
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index c087800d2a..e638dec767 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -2,7 +2,8 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
- "tasks": [{
+ "tasks": [
+ {
"label": "Build osu! (Debug)",
"type": "shell",
"command": "dotnet",
@@ -78,7 +79,8 @@
],
"group": "build",
"problemMatcher": "$msCompile"
- }, {
+ },
+ {
"label": "Build tournament tests (Release)",
"type": "shell",
"command": "dotnet",
@@ -94,6 +96,22 @@
"group": "build",
"problemMatcher": "$msCompile"
},
+ {
+ "label": "Build benchmarks",
+ "type": "shell",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "--no-restore",
+ "osu.Game.Benchmarks",
+ "/p:Configuration=Release",
+ "/p:GenerateFullPaths=true",
+ "/m",
+ "/verbosity:m"
+ ],
+ "group": "build",
+ "problemMatcher": "$msCompile"
+ },
{
"label": "Restore (netcoreapp3.1)",
"type": "shell",
diff --git a/Directory.Build.props b/Directory.Build.props
index 27a0bd0d48..21b8b402e0 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -40,7 +40,7 @@
https://github.com/ppy/osu
Automated release.
ppy Pty Ltd
- Copyright (c) 2019 ppy Pty Ltd
+ Copyright (c) 2020 ppy Pty Ltd
osu game
\ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
index ab594aee74..e3954c2681 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.1)
+ CFPropertyList (3.0.2)
addressable (2.7.0)
public_suffix (>= 2.0.2, < 5.0)
atomos (0.1.3)
@@ -18,8 +18,8 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.5)
emoji_regex (1.0.1)
- excon (0.67.0)
- faraday (0.15.4)
+ excon (0.71.1)
+ faraday (0.17.3)
multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6)
faraday (>= 0.7.4)
@@ -27,7 +27,7 @@ GEM
faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0)
fastimage (2.1.7)
- fastlane (2.133.0)
+ fastlane (2.140.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0)
@@ -36,13 +36,13 @@ GEM
commander-fastlane (>= 4.4.6, < 5.0.0)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 2.0)
- excon (>= 0.45.0, < 1.0.0)
- faraday (< 0.16.0)
+ excon (>= 0.71.0, < 1.0.0)
+ faraday (~> 0.17)
faraday-cookie_jar (~> 0.0.6)
- faraday_middleware (< 0.16.0)
+ faraday_middleware (~> 0.13.1)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
- google-api-client (>= 0.21.2, < 0.24.0)
+ google-api-client (>= 0.29.2, < 0.37.0)
google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0)
@@ -61,56 +61,58 @@ GEM
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
- xcodeproj (>= 1.8.1, < 2.0.0)
+ xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-clean_testflight_testers (0.3.0)
- fastlane-plugin-souyuz (0.8.1)
- souyuz (>= 0.8.1)
+ fastlane-plugin-souyuz (0.9.1)
+ souyuz (= 0.9.1)
fastlane-plugin-xamarin (0.6.3)
gh_inspector (1.1.3)
- google-api-client (0.23.9)
+ google-api-client (0.36.4)
addressable (~> 2.5, >= 2.5.1)
- googleauth (>= 0.5, < 0.7.0)
+ googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
- mime-types (~> 3.0)
+ mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
- signet (~> 0.9)
- google-cloud-core (1.3.1)
+ signet (~> 0.12)
+ google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
- google-cloud-env (1.2.1)
+ google-cloud-errors (~> 1.0)
+ google-cloud-env (1.3.0)
faraday (~> 0.11)
- google-cloud-storage (1.16.0)
+ google-cloud-errors (1.0.0)
+ google-cloud-storage (1.25.1)
+ addressable (~> 2.5)
digest-crc (~> 0.4)
- google-api-client (~> 0.23)
+ google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
- googleauth (>= 0.6.2, < 0.10.0)
- googleauth (0.6.7)
+ googleauth (~> 0.9)
+ mini_mime (~> 1.0)
+ googleauth (0.10.0)
faraday (~> 0.12)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
- signet (~> 0.7)
+ signet (~> 0.12)
highline (1.7.10)
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
- json (2.2.0)
+ json (2.3.0)
jwt (2.1.0)
- memoist (0.16.0)
- mime-types (3.3)
- mime-types-data (~> 3.2015)
- mime-types-data (3.2019.1009)
- mini_magick (4.9.5)
+ memoist (0.16.2)
+ mini_magick (4.10.1)
+ mini_mime (1.0.2)
mini_portile2 (2.4.0)
- multi_json (1.13.1)
+ multi_json (1.14.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
nanaimo (0.2.6)
naturally (2.2.0)
- nokogiri (1.10.4)
+ nokogiri (1.10.7)
mini_portile2 (~> 2.4.0)
os (1.0.1)
plist (3.5.0)
@@ -128,12 +130,12 @@ GEM
faraday (~> 0.9)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
- simctl (1.6.6)
+ simctl (1.6.7)
CFPropertyList
naturally
slack-notifier (2.3.2)
- souyuz (0.8.1)
- fastlane (>= 2.29.0)
+ souyuz (0.9.1)
+ fastlane (>= 1.103.0)
highline (~> 1.7)
nokogiri (~> 1.7)
terminal-notifier (2.0.0)
@@ -141,15 +143,15 @@ GEM
unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.7.0)
tty-screen (0.7.0)
- tty-spinner (0.9.1)
+ tty-spinner (0.9.2)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.6)
- unicode-display_width (1.6.0)
+ unicode-display_width (1.6.1)
word_wrap (1.0.0)
- xcodeproj (1.12.0)
+ xcodeproj (1.14.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
diff --git a/LICENCE b/LICENCE
index 21c6a7090f..2435c23545 100644
--- a/LICENCE
+++ b/LICENCE
@@ -1,4 +1,4 @@
-Copyright (c) 2019 ppy Pty Ltd .
+Copyright (c) 2020 ppy Pty Ltd .
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index 28a83fbbae..510b53054b 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -111,7 +111,6 @@ platform :ios do
souyuz(
platform: "ios",
- build_target: "osu_iOS",
plist_path: "../osu.iOS/Info.plist"
)
end
diff --git a/osu.Android.props b/osu.Android.props
index e1e6f2e478..494842f38f 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -54,6 +54,6 @@
-
+
diff --git a/osu.Desktop.slnf b/osu.Desktop.slnf
index e6b6446f72..d2c14d321a 100644
--- a/osu.Desktop.slnf
+++ b/osu.Desktop.slnf
@@ -3,6 +3,7 @@
"path": "osu.sln",
"projects": [
"osu.Desktop\\osu.Desktop.csproj",
+ "osu.Game.Benchmarks\\osu.Game.Benchmarks.csproj",
"osu.Game.Rulesets.Catch.Tests\\osu.Game.Rulesets.Catch.Tests.csproj",
"osu.Game.Rulesets.Catch\\osu.Game.Rulesets.Catch.csproj",
"osu.Game.Rulesets.Mania.Tests\\osu.Game.Rulesets.Mania.Tests.csproj",
diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs
index 80bb82c769..08cc0e7f5f 100644
--- a/osu.Desktop/DiscordRichPresence.cs
+++ b/osu.Desktop/DiscordRichPresence.cs
@@ -75,6 +75,9 @@ namespace osu.Desktop
private void updateStatus()
{
+ if (!client.IsInitialized)
+ return;
+
if (status.Value is UserStatusOffline)
{
client.ClearPresence();
diff --git a/osu.Desktop/Program.cs b/osu.Desktop/Program.cs
index 141b2cdbbc..bd91bcc933 100644
--- a/osu.Desktop/Program.cs
+++ b/osu.Desktop/Program.cs
@@ -22,8 +22,9 @@ namespace osu.Desktop
{
// Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory;
+ bool useSdl = args.Contains("--sdl");
- using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
+ using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true, useSdl: useSdl))
{
host.ExceptionThrown += handleException;
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index da47ad8223..b9294088f4 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/osu.Desktop/osu.nuspec b/osu.Desktop/osu.nuspec
index a26b35fcd5..a919d54f38 100644
--- a/osu.Desktop/osu.nuspec
+++ b/osu.Desktop/osu.nuspec
@@ -12,7 +12,7 @@
click the circles. to the beat.
click the circles.
testing
- Copyright (c) 2019 ppy Pty Ltd
+ Copyright (c) 2020 ppy Pty Ltd
en-AU
diff --git a/osu.Game.Benchmarks/BenchmarkBeatmapParsing.cs b/osu.Game.Benchmarks/BenchmarkBeatmapParsing.cs
new file mode 100644
index 0000000000..394fd75488
--- /dev/null
+++ b/osu.Game.Benchmarks/BenchmarkBeatmapParsing.cs
@@ -0,0 +1,37 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.IO;
+using BenchmarkDotNet.Attributes;
+using osu.Framework.IO.Stores;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Formats;
+using osu.Game.IO;
+using osu.Game.IO.Archives;
+using osu.Game.Resources;
+
+namespace osu.Game.Benchmarks
+{
+ public class BenchmarkBeatmapParsing : BenchmarkTest
+ {
+ private readonly MemoryStream beatmapStream = new MemoryStream();
+
+ public override void SetUp()
+ {
+ using (var resources = new DllResourceStore(OsuResources.ResourceAssembly))
+ using (var archive = resources.GetStream("Beatmaps/241526 Soleily - Renatus.osz"))
+ using (var reader = new ZipArchiveReader(archive))
+ reader.GetStream("Soleily - Renatus (Gamu) [Insane].osu").CopyTo(beatmapStream);
+ }
+
+ [Benchmark]
+ public Beatmap BenchmarkBundledBeatmap()
+ {
+ beatmapStream.Seek(0, SeekOrigin.Begin);
+ var reader = new LineBufferedReader(beatmapStream); // no disposal
+
+ var decoder = Decoder.GetDecoder(reader);
+ return decoder.Decode(reader);
+ }
+ }
+}
diff --git a/osu.Game.Benchmarks/BenchmarkTest.cs b/osu.Game.Benchmarks/BenchmarkTest.cs
new file mode 100644
index 0000000000..34f5edd084
--- /dev/null
+++ b/osu.Game.Benchmarks/BenchmarkTest.cs
@@ -0,0 +1,23 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Running;
+using NUnit.Framework;
+
+namespace osu.Game.Benchmarks
+{
+ [TestFixture]
+ [MemoryDiagnoser]
+ public abstract class BenchmarkTest
+ {
+ [GlobalSetup]
+ [OneTimeSetUp]
+ public virtual void SetUp()
+ {
+ }
+
+ [Test]
+ public void RunBenchmark() => BenchmarkRunner.Run(GetType());
+ }
+}
diff --git a/osu.Game.Benchmarks/Program.cs b/osu.Game.Benchmarks/Program.cs
new file mode 100644
index 0000000000..c55075fea6
--- /dev/null
+++ b/osu.Game.Benchmarks/Program.cs
@@ -0,0 +1,17 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using BenchmarkDotNet.Running;
+
+namespace osu.Game.Benchmarks
+{
+ public static class Program
+ {
+ public static void Main(string[] args)
+ {
+ BenchmarkSwitcher
+ .FromAssembly(typeof(Program).Assembly)
+ .Run(args);
+ }
+ }
+}
diff --git a/osu.Game.Benchmarks/Properties/launchSettings.json b/osu.Game.Benchmarks/Properties/launchSettings.json
new file mode 100644
index 0000000000..c1868088f9
--- /dev/null
+++ b/osu.Game.Benchmarks/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "All Benchmarks": {
+ "commandName": "Project",
+ "commandLineArgs": "--filter *"
+ }
+ }
+}
\ No newline at end of file
diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
new file mode 100644
index 0000000000..f2e1c0ec3b
--- /dev/null
+++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netcoreapp3.1
+ Exe
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
index 493ac7ae39..f4749be370 100644
--- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs
@@ -5,7 +5,7 @@ using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using NUnit.Framework;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Catch.Mods;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 9559d13328..8c371db257 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
index 8377b3786a..e2465d727e 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModDifficultyAdjust.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModDifficultyAdjust : ModDifficultyAdjust
{
- [SettingSource("Fruit Size", "Override a beatmap's set CS.")]
+ [SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1)]
public BindableNumber CircleSize { get; } = new BindableFloat
{
Precision = 0.1f,
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Catch.Mods
Value = 5,
};
- [SettingSource("Approach Rate", "Override a beatmap's set AR.")]
+ [SettingSource("Approach Rate", "Override a beatmap's set AR.", LAST_SETTING_ORDER + 1)]
public BindableNumber ApproachRate { get; } = new BindableFloat
{
Precision = 0.1f,
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
index a47efcc10a..4c72b9fd3e 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs
@@ -36,7 +36,10 @@ namespace osu.Game.Rulesets.Catch.Mods
//disable keyboard controls
public bool OnPressed(CatchAction action) => true;
- public bool OnReleased(CatchAction action) => true;
+
+ public void OnReleased(CatchAction action)
+ {
+ }
protected override bool OnMouseMove(MouseMoveEvent e)
{
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 267e6d12c7..0c754412e5 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -36,7 +36,11 @@ namespace osu.Game.Rulesets.Catch.Objects
}
}
- public double EndTime => StartTime + Duration;
+ public double EndTime
+ {
+ get => StartTime + Duration;
+ set => Duration = value - StartTime;
+ }
public double Duration { get; set; }
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
index 958cd19d50..53a018c9f4 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
using osuTK;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index a4ed966abb..b014b32305 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -110,7 +110,11 @@ namespace osu.Game.Rulesets.Catch.Objects
}
}
- public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity;
+ public double EndTime
+ {
+ get => StartTime + this.SpanCount() * Path.Distance / Velocity;
+ set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
+ }
public float EndX => X + this.CurvePositionAt(1).X / CatchPlayfield.BASE_WIDTH;
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
index 6c8515eb90..4649dcae90 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchAutoGenerator.cs
@@ -3,7 +3,7 @@
using System;
using System.Linq;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Replays;
using osu.Game.Rulesets.Catch.Beatmaps;
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
index 22532bc9ec..f122588a2b 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Input.StateChanges;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 589503c35b..2d71fb93fb 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -20,7 +20,9 @@ namespace osu.Game.Rulesets.Catch.UI
internal readonly CatcherArea CatcherArea;
- public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => base.ReceivePositionalInputAt(screenSpacePos) || CatcherArea.ReceivePositionalInputAt(screenSpacePos);
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
+ // only check the X position; handle all vertical space.
+ base.ReceivePositionalInputAt(new Vector2(screenSpacePos.X, ScreenSpaceDrawQuad.Centre.Y));
public CatchPlayfield(BeatmapDifficulty difficulty, Func> createDrawableRepresentation)
{
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 2d6ce02e45..1de0b6bfa3 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -7,7 +7,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Bindings;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
@@ -103,7 +103,9 @@ namespace osu.Game.Rulesets.Catch.UI
MovableCatcher.X = state.CatcherX.Value;
}
- public bool OnReleased(CatchAction action) => false;
+ public void OnReleased(CatchAction action)
+ {
+ }
public bool AttemptCatch(CatchHitObject obj) => MovableCatcher.AttemptCatch(obj);
@@ -341,24 +343,22 @@ namespace osu.Game.Rulesets.Catch.UI
return false;
}
- public bool OnReleased(CatchAction action)
+ public void OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
- return true;
+ break;
case CatchAction.MoveRight:
currentDirection--;
- return true;
+ break;
case CatchAction.Dash:
Dashing = false;
- return true;
+ break;
}
-
- return false;
}
///
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
index 12865385b6..d0ff1fab43 100644
--- a/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaBeatmapConversionTest.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index dea6e6c0fb..6855b99f28 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
index 1a77a4944b..d904474815 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
@@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mania.Objects;
using System;
using System.Linq;
using System.Collections.Generic;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
index 9565ac8994..315ef96e49 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/Patterns/Legacy/DistanceObjectPatternGenerator.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.MathUtils;
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs
index bcbc1ee527..7bbde400ea 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/HoldNotePlacementBlueprint.cs
@@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
base.UpdatePosition(screenSpacePosition);
- if (PlacementBegun)
+ if (PlacementActive)
{
var endTime = TimeAt(screenSpacePosition);
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs
index b28d8bb0e6..a3657d3bb9 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaPlacementBlueprint.cs
@@ -54,15 +54,15 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
return true;
}
- protected override bool OnMouseUp(MouseUpEvent e)
+ protected override void OnMouseUp(MouseUpEvent e)
{
- EndPlacement();
- return base.OnMouseUp(e);
+ EndPlacement(true);
+ base.OnMouseUp(e);
}
public override void UpdatePosition(Vector2 screenSpacePosition)
{
- if (!PlacementBegun)
+ if (!PlacementActive)
Column = ColumnAt(screenSpacePosition);
if (Column == null) return;
diff --git a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs
index 3bd7fb2d49..9f57160f99 100644
--- a/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Blueprints/ManiaSelectionBlueprint.cs
@@ -13,7 +13,7 @@ using osuTK;
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
{
- public class ManiaSelectionBlueprint : SelectionBlueprint
+ public class ManiaSelectionBlueprint : OverlaySelectionBlueprint
{
public Vector2 ScreenSpaceDragPosition { get; private set; }
public Vector2 DragPosition { get; private set; }
@@ -55,14 +55,12 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
return base.OnMouseDown(e);
}
- protected override bool OnDrag(DragEvent e)
+ protected override void OnDrag(DragEvent e)
{
- var result = base.OnDrag(e);
+ base.OnDrag(e);
ScreenSpaceDragPosition = e.ScreenSpaceMousePosition;
DragPosition = DrawableObject.ToLocalSpace(e.ScreenSpaceMousePosition);
-
- return result;
}
public override void Show()
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs
new file mode 100644
index 0000000000..d744036b4c
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaBlueprintContainer.cs
@@ -0,0 +1,34 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Mania.Edit.Blueprints;
+using osu.Game.Rulesets.Mania.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Screens.Edit.Compose.Components;
+
+namespace osu.Game.Rulesets.Mania.Edit
+{
+ public class ManiaBlueprintContainer : ComposeBlueprintContainer
+ {
+ public ManiaBlueprintContainer(IEnumerable drawableHitObjects)
+ : base(drawableHitObjects)
+ {
+ }
+
+ public override OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
+ {
+ switch (hitObject)
+ {
+ case DrawableNote note:
+ return new NoteSelectionBlueprint(note);
+
+ case DrawableHoldNote holdNote:
+ return new HoldNoteSelectionBlueprint(holdNote);
+ }
+
+ return base.CreateBlueprintFor(hitObject);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
index 1632b6a583..62b609610f 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
@@ -5,11 +5,8 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.Objects.Drawables;
-using osu.Game.Rulesets.Objects.Drawables;
using System.Collections.Generic;
using osu.Framework.Allocation;
-using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
@@ -52,26 +49,12 @@ namespace osu.Game.Rulesets.Mania.Edit
return drawableRuleset;
}
+ protected override ComposeBlueprintContainer CreateBlueprintContainer() => new ManiaBlueprintContainer(drawableRuleset.Playfield.AllHitObjects);
+
protected override IReadOnlyList CompositionTools => new HitObjectCompositionTool[]
{
new NoteCompositionTool(),
new HoldNoteCompositionTool()
};
-
- public override SelectionHandler CreateSelectionHandler() => new ManiaSelectionHandler();
-
- public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
- {
- switch (hitObject)
- {
- case DrawableNote note:
- return new NoteSelectionBlueprint(note);
-
- case DrawableHoldNote holdNote:
- return new HoldNoteSelectionBlueprint(holdNote);
- }
-
- return base.CreateBlueprintFor(hitObject);
- }
}
}
diff --git a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
index 618af3e772..9069a636a8 100644
--- a/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
+++ b/osu.Game.Rulesets.Mania/Edit/ManiaSelectionHandler.cs
@@ -5,6 +5,7 @@ using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Timing;
+using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Mania.Edit.Blueprints;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI;
@@ -70,10 +71,12 @@ namespace osu.Game.Rulesets.Mania.Edit
// When scrolling downwards the anchor position is at the bottom of the screen, however the movement event assumes the anchor is at the top of the screen.
// This causes the delta to assume a positive hitobject position, and which can be corrected for by subtracting the parent height.
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
- delta -= moveEvent.Blueprint.DrawableObject.Parent.DrawHeight;
+ delta -= moveEvent.Blueprint.Parent.DrawHeight; // todo: probably wrong
- foreach (var b in SelectedBlueprints)
+ foreach (var selectionBlueprint in SelectedBlueprints)
{
+ var b = (OverlaySelectionBlueprint)selectionBlueprint;
+
var hitObject = b.DrawableObject;
var objectParent = (HitObjectContainer)hitObject.Parent;
diff --git a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs
index ff8882124f..433db79ae0 100644
--- a/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Mania/Edit/Masks/ManiaSelectionBlueprint.cs
@@ -7,7 +7,7 @@ using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Game.Rulesets.Mania.Edit.Masks
{
- public abstract class ManiaSelectionBlueprint : SelectionBlueprint
+ public abstract class ManiaSelectionBlueprint : OverlaySelectionBlueprint
{
protected ManiaSelectionBlueprint(DrawableHitObject drawableObject)
: base(drawableObject)
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index 02c2158383..b7b523a94d 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -237,19 +237,19 @@ namespace osu.Game.Rulesets.Mania
{
LeftKeys = new[]
{
- InputKey.Number1,
- InputKey.Number2,
- InputKey.Number3,
- InputKey.Number4,
+ InputKey.Q,
+ InputKey.W,
+ InputKey.E,
+ InputKey.R,
},
RightKeys = new[]
{
- InputKey.Z,
InputKey.X,
InputKey.C,
- InputKey.V
+ InputKey.V,
+ InputKey.B
},
- SpecialKey = InputKey.Tilde,
+ SpecialKey = InputKey.S,
SpecialAction = ManiaAction.Special1,
NormalActionStart = ManiaAction.Key1
}.GenerateKeyBindingsFor(keys, out var nextNormal);
@@ -265,12 +265,12 @@ namespace osu.Game.Rulesets.Mania
},
RightKeys = new[]
{
- InputKey.O,
- InputKey.P,
- InputKey.BracketLeft,
- InputKey.BracketRight
+ InputKey.K,
+ InputKey.L,
+ InputKey.Semicolon,
+ InputKey.Quote
},
- SpecialKey = InputKey.BackSlash,
+ SpecialKey = InputKey.I,
SpecialAction = ManiaAction.Special2,
NormalActionStart = nextNormal
}.GenerateKeyBindingsFor(keys, out _);
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
index 39185e6a57..4c125ad6ef 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFadeIn.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Mania.Mods
{
public override string Name => "Fade In";
public override string Acronym => "FI";
- public override IconUsage Icon => OsuIcon.ModHidden;
+ public override IconUsage? Icon => OsuIcon.ModHidden;
public override ModType Type => ModType.DifficultyIncrease;
public override string Description => @"Keys appear out of nowhere!";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
index 9275371a61..14b36fb765 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
@@ -4,7 +4,7 @@
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Sprites;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Beatmaps;
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Name => "Random";
public override string Acronym => "RD";
public override ModType Type => ModType.Conversion;
- public override IconUsage Icon => OsuIcon.Dice;
+ public override IconUsage? Icon => OsuIcon.Dice;
public override string Description => @"Shuffle around the keys!";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index 155adb958b..14a7c5fda3 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -171,17 +171,17 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
bodyPiece.Hitting = true;
}
- public bool OnReleased(ManiaAction action)
+ public void OnReleased(ManiaAction action)
{
if (AllJudged)
- return false;
+ return;
if (action != Action.Value)
- return false;
+ return;
// Make sure a hold was started
if (HoldStartTime == null)
- return false;
+ return;
Tail.UpdateResult();
endHold();
@@ -189,8 +189,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
// If the key has been released too early, the user should not receive full score for the release
if (!Tail.IsHit)
HasBroken = true;
-
- return true;
}
private void endHold()
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs
index a5d03bf765..390c64c5e2 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs
@@ -17,6 +17,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note
- public override bool OnReleased(ManiaAction action) => false; // Handled by the hold note
+ public override void OnReleased(ManiaAction action)
+ {
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs
index a660144dd1..568b07c958 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteTail.cs
@@ -59,6 +59,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note
- public override bool OnReleased(ManiaAction action) => false; // Handled by the hold note
+ public override void OnReleased(ManiaAction action)
+ {
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
index 8f353ae138..85613d3afb 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs
@@ -77,6 +77,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
return UpdateResult(true);
}
- public virtual bool OnReleased(ManiaAction action) => false;
+ public virtual void OnReleased(ManiaAction action)
+ {
+ }
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index bdba813eed..86d3d2b2b0 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -15,7 +15,11 @@ namespace osu.Game.Rulesets.Mania.Objects
///
public class HoldNote : ManiaHitObject, IHasEndTime
{
- public double EndTime => StartTime + Duration;
+ public double EndTime
+ {
+ get => StartTime + Duration;
+ set => Duration = value - StartTime;
+ }
private double duration;
diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs
index 3d2a070b0f..63c573d344 100644
--- a/osu.Game.Rulesets.Mania/UI/Column.cs
+++ b/osu.Game.Rulesets.Mania/UI/Column.cs
@@ -191,7 +191,9 @@ namespace osu.Game.Rulesets.Mania.UI
return true;
}
- public bool OnReleased(ManiaAction action) => false;
+ public void OnReleased(ManiaAction action)
+ {
+ }
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
// This probably shouldn't exist as is, but the columns in the stage are separated by a 1px border
diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs
index 57241da564..75cc351310 100644
--- a/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs
+++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnBackground.cs
@@ -98,11 +98,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components
return false;
}
- public bool OnReleased(ManiaAction action)
+ public void OnReleased(ManiaAction action)
{
if (action == this.action.Value)
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
- return false;
}
}
}
diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs
index ee2cec1bbd..90e78c3899 100644
--- a/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs
+++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnHitObjectArea.cs
@@ -18,8 +18,6 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{
public class ColumnHitObjectArea : CompositeDrawable, IHasAccentColour
{
- private const float hit_target_bar_height = 2;
-
private readonly IBindable direction = new Bindable();
private readonly Drawable hitTarget;
@@ -67,6 +65,8 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private class DefaultHitTarget : CompositeDrawable, IHasAccentColour
{
+ private const float hit_target_bar_height = 2;
+
private readonly IBindable direction = new Bindable();
private readonly Container hitTargetLine;
diff --git a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs
index 85880222d7..60fc2713b3 100644
--- a/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs
+++ b/osu.Game.Rulesets.Mania/UI/Components/ColumnKeyArea.cs
@@ -115,11 +115,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components
return false;
}
- public bool OnReleased(ManiaAction action)
+ public void OnReleased(ManiaAction action)
{
if (action == this.action.Value)
keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
- return false;
}
}
}
diff --git a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
index ccbff226a9..35de47e208 100644
--- a/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Mania/UI/HitExplosion.cs
@@ -5,7 +5,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
using osuTK;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
index 450f7de6d2..cd3daf18a9 100644
--- a/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Osu.Tests/OsuBeatmapConversionTest.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Beatmaps;
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs
index 4676f14655..3ff37c4147 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneLegacyBeatmapSkin.cs
@@ -7,12 +7,10 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.Graphics;
using osu.Framework.IO.Stores;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Screens;
using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
@@ -21,7 +19,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Tests
{
- public class TestSceneLegacyBeatmapSkin : OsuTestScene
+ public class TestSceneLegacyBeatmapSkin : ScreenTestScene
{
[Resolved]
private AudioManager audio { get; set; }
@@ -65,7 +63,8 @@ namespace osu.Game.Rulesets.Osu.Tests
ExposedPlayer player;
Beatmap.Value = new CustomSkinWorkingBeatmap(audio, beatmapHasColours);
- Child = new OsuScreenStack(player = new ExposedPlayer(userHasCustomColours)) { RelativeSizeAxes = Axes.Both };
+
+ LoadScreen(player = new ExposedPlayer(userHasCustomColours));
return player;
}
@@ -90,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public IReadOnlyList UsableComboColours =>
GameplayClockContainer.ChildrenOfType()
.First()
- .GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value;
+ .GetConfig>(GlobalSkinColours.ComboColours)?.Value;
}
private class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs
index c9b3d08a22..4af4d5f966 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuDistanceSnapGrid.cs
@@ -9,7 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Beatmaps;
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs
index 863d0eda09..d692be89b2 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneShaking.cs
@@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Diagnostics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring;
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
index b6fc9821a4..94df239267 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderInput.cs
@@ -44,6 +44,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private const double time_during_slide_2 = 3000;
private const double time_during_slide_3 = 3500;
private const double time_during_slide_4 = 3800;
+ private const double time_slider_end = 4000;
private List judgementResults;
private bool allJudgedFired;
@@ -284,6 +285,48 @@ namespace osu.Game.Rulesets.Osu.Tests
AddAssert("Tracking acquired", assertMidSliderJudgements);
}
+ ///
+ /// Scenario:
+ /// - Press a key on the slider head
+ /// - While holding the key, move cursor close to the edge of tracking area
+ /// - Keep the cursor on the edge of tracking area until the slider ends
+ /// Expected Result:
+ /// A passing test case will have the slider track the cursor throughout the whole test.
+ ///
+ [Test]
+ public void TestTrackingAreaEdge()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, OsuHitObject.OBJECT_RADIUS * 1.19f), Actions = { OsuAction.LeftButton }, Time = time_slider_start + 250 },
+ new OsuReplayFrame { Position = new Vector2(slider_path_length, OsuHitObject.OBJECT_RADIUS * 1.199f), Actions = { OsuAction.LeftButton }, Time = time_slider_end },
+ });
+
+ AddAssert("Tracking kept", assertGreatJudge);
+ }
+
+ ///
+ /// Scenario:
+ /// - Press a key on the slider head
+ /// - While holding the key, move cursor just outside the tracking area
+ /// - Keep the cursor just outside the tracking area until the slider ends
+ /// Expected Result:
+ /// A passing test case will have the slider drop the tracking on frame 2.
+ ///
+ [Test]
+ public void TestTrackingAreaOutsideEdge()
+ {
+ performTest(new List
+ {
+ new OsuReplayFrame { Position = new Vector2(0, 0), Actions = { OsuAction.LeftButton }, Time = time_slider_start },
+ new OsuReplayFrame { Position = new Vector2(0, OsuHitObject.OBJECT_RADIUS * 1.21f), Actions = { OsuAction.LeftButton }, Time = time_slider_start + 250 },
+ new OsuReplayFrame { Position = new Vector2(slider_path_length, OsuHitObject.OBJECT_RADIUS * 1.201f), Actions = { OsuAction.LeftButton }, Time = time_slider_end },
+ });
+
+ AddAssert("Tracking dropped", assertMidSliderJudgementFail);
+ }
+
private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;
@@ -294,6 +337,8 @@ namespace osu.Game.Rulesets.Osu.Tests
private ScoreAccessibleReplayPlayer currentPlayer;
+ private const float slider_path_length = 25;
+
private void performTest(List frames)
{
AddStep("load player", () =>
@@ -309,8 +354,8 @@ namespace osu.Game.Rulesets.Osu.Tests
Path = new SliderPath(PathType.PerfectCurve, new[]
{
Vector2.Zero,
- new Vector2(25, 0),
- }, 25),
+ new Vector2(slider_path_length, 0),
+ }, slider_path_length),
}
},
BeatmapInfo =
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs
index 013920684c..5dd2bd18a8 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderSelectionBlueprint.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Objects;
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
index bd9d948782..5cf571d961 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index 1d8c4708c1..217707b180 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -2,9 +2,9 @@
-
+
-
+
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs
index bb47c7e464..407f5f540e 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/HitCircles/HitCirclePlacementBlueprint.cs
@@ -30,12 +30,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
protected override bool OnClick(ClickEvent e)
{
- EndPlacement();
+ EndPlacement(true);
return true;
}
public override void UpdatePosition(Vector2 screenSpacePosition)
{
+ BeginPlacement();
HitObject.Position = ToLocalSpace(screenSpacePosition);
}
}
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs
index a864257274..b0e13808a5 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/OsuSelectionBlueprint.cs
@@ -7,10 +7,10 @@ using osu.Game.Rulesets.Osu.Objects;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints
{
- public abstract class OsuSelectionBlueprint : SelectionBlueprint
+ public abstract class OsuSelectionBlueprint : OverlaySelectionBlueprint
where T : OsuHitObject
{
- protected T HitObject => (T)DrawableObject.HitObject;
+ protected new T HitObject => (T)DrawableObject.HitObject;
protected OsuSelectionBlueprint(DrawableHitObject drawableObject)
: base(drawableObject)
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs
index 6a0730db91..af4da5e853 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs
@@ -135,13 +135,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
return false;
}
- protected override bool OnMouseUp(MouseUpEvent e) => RequestSelection != null;
-
protected override bool OnClick(ClickEvent e) => RequestSelection != null;
protected override bool OnDragStart(DragStartEvent e) => e.Button == MouseButton.Left;
- protected override bool OnDrag(DragEvent e)
+ protected override void OnDrag(DragEvent e)
{
if (ControlPoint == slider.Path.ControlPoints[0])
{
@@ -158,12 +156,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
}
else
ControlPoint.Position.Value += e.Delta;
-
- return true;
}
- protected override bool OnDragEnd(DragEndEvent e) => true;
-
///
/// Updates the state of the circular control point marker.
///
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
index 6f583d7983..e293eba9d7 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs
@@ -108,7 +108,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
return false;
}
- public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete;
+ public void OnReleased(PlatformAction action)
+ {
+ }
private void selectPiece(PathControlPointPiece piece, MouseButtonEvent e)
{
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs
index f09279ed73..a0392fe536 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderCircleSelectionBlueprint.cs
@@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
: base(slider)
{
this.position = position;
+
InternalChild = CirclePiece = new HitCirclePiece();
Select();
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs
index 2497e428fc..a780653796 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs
@@ -68,6 +68,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
switch (state)
{
case PlacementState.Initial:
+ BeginPlacement();
HitObject.Position = ToLocalSpace(screenSpacePosition);
break;
@@ -106,11 +107,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
return true;
}
- protected override bool OnMouseUp(MouseUpEvent e)
+ protected override void OnMouseUp(MouseUpEvent e)
{
if (state == PlacementState.Body && e.Button == MouseButton.Right)
endCurve();
- return base.OnMouseUp(e);
+ base.OnMouseUp(e);
}
protected override bool OnDoubleClick(DoubleClickEvent e)
@@ -125,14 +126,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private void beginCurve()
{
- BeginPlacement();
+ BeginPlacement(commitStart: true);
setState(PlacementState.Body);
}
private void endCurve()
{
updateSlider();
- EndPlacement();
+ EndPlacement(true);
}
protected override void Update()
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
index 3165c441fb..c18b3b0ff3 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs
@@ -90,19 +90,16 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
protected override bool OnDragStart(DragStartEvent e) => placementControlPointIndex != null;
- protected override bool OnDrag(DragEvent e)
+ protected override void OnDrag(DragEvent e)
{
Debug.Assert(placementControlPointIndex != null);
HitObject.Path.ControlPoints[placementControlPointIndex.Value].Position.Value = e.MousePosition - HitObject.Position;
-
- return true;
}
- protected override bool OnDragEnd(DragEndEvent e)
+ protected override void OnDragEnd(DragEndEvent e)
{
placementControlPointIndex = null;
- return true;
}
private BindableList controlPoints => HitObject.Path.ControlPoints;
@@ -173,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)),
};
- public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint;
+ public override Vector2 SelectionPoint => ((DrawableSlider)DrawableObject).HeadCircle.ScreenSpaceDrawQuad.Centre;
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos);
diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs
index 5525b8936e..74b563d922 100644
--- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs
+++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Spinners/SpinnerPlacementBlueprint.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
using osu.Game.Rulesets.Edit;
@@ -8,6 +9,7 @@ using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.UI;
using osuTK;
+using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
{
@@ -29,22 +31,31 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
{
base.Update();
+ if (isPlacingEnd)
+ HitObject.EndTime = Math.Max(HitObject.StartTime, EditorClock.CurrentTime);
+
piece.UpdateFrom(HitObject);
}
- protected override bool OnClick(ClickEvent e)
+ protected override bool OnMouseDown(MouseDownEvent e)
{
if (isPlacingEnd)
{
+ if (e.Button != MouseButton.Right)
+ return false;
+
HitObject.EndTime = EditorClock.CurrentTime;
- EndPlacement();
+ EndPlacement(true);
}
else
{
- isPlacingEnd = true;
+ if (e.Button != MouseButton.Left)
+ return false;
+
+ BeginPlacement(commitStart: true);
piece.FadeTo(1f, 150, Easing.OutQuint);
- BeginPlacement();
+ isPlacingEnd = true;
}
return true;
diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs
index 22b4c3e82e..a8719e0aa8 100644
--- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs
+++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs
@@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Osu.Edit
if (existing == null)
return;
+ hitObject.RemoveTransform(existing);
+
using (hitObject.BeginAbsoluteSequence(existing.StartTime))
hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire();
break;
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs
new file mode 100644
index 0000000000..330f34b85c
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Edit/OsuBlueprintContainer.cs
@@ -0,0 +1,41 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Game.Rulesets.Edit;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
+using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
+using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Screens.Edit.Compose.Components;
+
+namespace osu.Game.Rulesets.Osu.Edit
+{
+ public class OsuBlueprintContainer : ComposeBlueprintContainer
+ {
+ public OsuBlueprintContainer(IEnumerable drawableHitObjects)
+ : base(drawableHitObjects)
+ {
+ }
+
+ protected override SelectionHandler CreateSelectionHandler() => new OsuSelectionHandler();
+
+ public override OverlaySelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
+ {
+ switch (hitObject)
+ {
+ case DrawableHitCircle circle:
+ return new HitCircleSelectionBlueprint(circle);
+
+ case DrawableSlider slider:
+ return new SliderSelectionBlueprint(slider);
+
+ case DrawableSpinner spinner:
+ return new SpinnerSelectionBlueprint(spinner);
+ }
+
+ return base.CreateBlueprintFor(hitObject);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs
index 49624ea733..cdf78a5902 100644
--- a/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs
+++ b/osu.Game.Rulesets.Osu/Edit/OsuHitObjectComposer.cs
@@ -9,12 +9,7 @@ using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
-using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles;
-using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders;
-using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners;
using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.UI;
using osu.Game.Screens.Edit.Compose.Components;
@@ -37,27 +32,13 @@ namespace osu.Game.Rulesets.Osu.Edit
new SpinnerCompositionTool()
};
- public override SelectionHandler CreateSelectionHandler() => new OsuSelectionHandler();
-
- public override SelectionBlueprint CreateBlueprintFor(DrawableHitObject hitObject)
- {
- switch (hitObject)
- {
- case DrawableHitCircle circle:
- return new HitCircleSelectionBlueprint(circle);
-
- case DrawableSlider slider:
- return new SliderSelectionBlueprint(slider);
-
- case DrawableSpinner spinner:
- return new SpinnerSelectionBlueprint(spinner);
- }
-
- return base.CreateBlueprintFor(hitObject);
- }
+ protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(HitObjects);
protected override DistanceSnapGrid CreateDistanceSnapGrid(IEnumerable selectedHitObjects)
{
+ if (BlueprintContainer.CurrentTool is SpinnerCompositionTool)
+ return null;
+
var objects = selectedHitObjects.ToList();
if (objects.Count == 0)
@@ -111,6 +92,9 @@ namespace osu.Game.Rulesets.Osu.Edit
targetIndex++;
}
+ if (sourceObject is Spinner)
+ return null;
+
return new OsuDistanceSnapGrid((OsuHitObject)sourceObject, (OsuHitObject)targetObject);
}
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs
index 65d7acc911..fe46876050 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModAutopilot.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Autopilot";
public override string Acronym => "AP";
- public override IconUsage Icon => OsuIcon.ModAutopilot;
+ public override IconUsage? Icon => OsuIcon.ModAutopilot;
public override ModType Type => ModType.Automation;
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs
index 831e4a700f..937473e824 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Description => "Play with blinds on your screen.";
public override string Acronym => "BL";
- public override IconUsage Icon => FontAwesome.Solid.Adjust;
+ public override IconUsage? Icon => FontAwesome.Solid.Adjust;
public override ModType Type => ModType.DifficultyIncrease;
public override bool Ranked => false;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
index 9bf7525d33..73cb483ef0 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDeflate.cs
@@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "DF";
- public override IconUsage Icon => FontAwesome.Solid.CompressArrowsAlt;
+ public override IconUsage? Icon => FontAwesome.Solid.CompressArrowsAlt;
public override string Description => "Hit them at the right size!";
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
index 7eee71be81..75de6896a3 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModDifficultyAdjust.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModDifficultyAdjust : ModDifficultyAdjust
{
- [SettingSource("Circle Size", "Override a beatmap's set CS.")]
+ [SettingSource("Circle Size", "Override a beatmap's set CS.", FIRST_SETTING_ORDER - 1)]
public BindableNumber CircleSize { get; } = new BindableFloat
{
Precision = 0.1f,
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
Value = 5,
};
- [SettingSource("Approach Rate", "Override a beatmap's set AR.")]
+ [SettingSource("Approach Rate", "Override a beatmap's set AR.", LAST_SETTING_ORDER + 1)]
public BindableNumber ApproachRate { get; } = new BindableFloat
{
Precision = 0.1f,
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
index 778c2f7d43..ac20407ed2 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModFlashlight.cs
@@ -8,7 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
index 76676ce888..f08d4e8f5e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModGrow.cs
@@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Acronym => "GR";
- public override IconUsage Icon => FontAwesome.Solid.ArrowsAltV;
+ public override IconUsage? Icon => FontAwesome.Solid.ArrowsAltV;
public override string Description => "Hit them at the right size!";
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
index eae218509e..940c888f3a 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpinIn.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Spin In";
public override string Acronym => "SI";
- public override IconUsage Icon => FontAwesome.Solid.Undo;
+ public override IconUsage? Icon => FontAwesome.Solid.Undo;
public override ModType Type => ModType.Fun;
public override string Description => "Circles spin in. No approach circles.";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
index 1cdcddbd33..9d5d300a9e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Spun Out";
public override string Acronym => "SO";
- public override IconUsage Icon => OsuIcon.ModSpunout;
+ public override IconUsage? Icon => OsuIcon.ModSpunout;
public override ModType Type => ModType.DifficultyReduction;
public override string Description => @"Spinners will be automatically completed.";
public override double ScoreMultiplier => 0.9;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
index 8360e2692e..2464308347 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Name => "Target";
public override string Acronym => "TP";
public override ModType Type => ModType.Conversion;
- public override IconUsage Icon => OsuIcon.ModTarget;
+ public override IconUsage? Icon => OsuIcon.ModTarget;
public override string Description => @"Practice keeping up with the beat of the song.";
public override double ScoreMultiplier => 1;
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs
index dff9a77807..774f9cf58b 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTraceable.cs
@@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework.Bindables;
using System.Collections.Generic;
using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
@@ -19,7 +18,6 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Traceable";
public override string Acronym => "TC";
- public override IconUsage Icon => FontAwesome.Brands.SnapchatGhost;
public override ModType Type => ModType.Fun;
public override string Description => "Put your faith in the approach circles...";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
index a9475af638..cc664ae72e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTransform.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Transform";
public override string Acronym => "TR";
- public override IconUsage Icon => FontAwesome.Solid.ArrowsAlt;
+ public override IconUsage? Icon => FontAwesome.Solid.ArrowsAlt;
public override ModType Type => ModType.Fun;
public override string Description => "Everything rotates. EVERYTHING.";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
index 1664a37a66..cc2f4c3f70 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModWiggle.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Wiggle";
public override string Acronym => "WG";
- public override IconUsage Icon => FontAwesome.Solid.Certificate;
+ public override IconUsage? Icon => FontAwesome.Solid.Certificate;
public override ModType Type => ModType.Fun;
public override string Description => "They just won't stay still...";
public override double ScoreMultiplier => 1;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
index 6c4fbbac17..a5e89210f6 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
///
/// The start time of .
///
- public readonly Bindable StartTime = new Bindable();
+ public readonly Bindable StartTime = new BindableDouble();
///
/// The which s will exit from.
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
index f74f2d7bc5..4ef63bb2a0 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableHitCircle.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly IBindable positionBindable = new Bindable();
private readonly IBindable stackHeightBindable = new Bindable();
- private readonly IBindable scaleBindable = new Bindable();
+ private readonly IBindable scaleBindable = new BindableFloat();
public OsuAction? HitAction => HitArea.HitAction;
@@ -205,7 +205,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
return false;
}
- public bool OnReleased(OsuAction action) => false;
+ public void OnReleased(OsuAction action)
+ {
+ }
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
index b81d94a673..8fdcd060e7 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
@@ -6,13 +6,11 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using osu.Game.Rulesets.Scoring;
using osuTK;
-using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -23,7 +21,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private double animDuration;
- private readonly SkinnableDrawable scaleContainer;
+ private readonly Drawable scaleContainer;
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
: base(repeatPoint)
@@ -36,19 +34,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Blending = BlendingParameters.Additive;
Origin = Anchor.Centre;
- InternalChild = scaleContainer = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon
- {
- RelativeSizeAxes = Axes.Both,
- Icon = FontAwesome.Solid.ChevronRight,
- Size = new Vector2(0.35f)
- }, confineMode: ConfineMode.NoScaling)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- };
+ InternalChild = scaleContainer = new ReverseArrowPiece();
}
- private readonly IBindable scaleBindable = new Bindable();
+ private readonly IBindable scaleBindable = new BindableFloat();
[BackgroundDependencyLoader]
private void load()
@@ -65,11 +54,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void UpdateInitialTransforms()
{
- animDuration = Math.Min(150, repeatPoint.SpanDuration / 2);
+ animDuration = Math.Min(300, repeatPoint.SpanDuration);
this.Animate(
d => d.FadeIn(animDuration),
- d => d.ScaleTo(0.5f).ScaleTo(1f, animDuration * 4, Easing.OutElasticHalf)
+ d => d.ScaleTo(0.5f).ScaleTo(1f, animDuration * 2, Easing.OutElasticHalf)
);
}
@@ -88,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
break;
case ArmedState.Hit:
- this.FadeOut(animDuration, Easing.OutQuint)
+ this.FadeOut(animDuration, Easing.Out)
.ScaleTo(Scale * 1.5f, animDuration, Easing.Out);
break;
}
@@ -121,7 +110,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
break;
}
- float aimRotation = MathHelper.RadiansToDegrees(MathF.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
+ float aimRotation = MathUtils.RadiansToDegrees(MathF.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
while (Math.Abs(aimRotation - Rotation) > 180)
aimRotation += aimRotation < Rotation ? 360 : -360;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index cd3c572ba0..7403649184 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly IBindable positionBindable = new Bindable();
private readonly IBindable stackHeightBindable = new Bindable();
- private readonly IBindable scaleBindable = new Bindable();
+ private readonly IBindable scaleBindable = new BindableFloat();
public DrawableSlider(Slider s)
: base(s)
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
index 9d4d9958a1..60b5c335d6 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderTick.cs
@@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
};
}
- private readonly IBindable scaleBindable = new Bindable();
+ private readonly IBindable scaleBindable = new BindableFloat();
[BackgroundDependencyLoader]
private void load()
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs
new file mode 100644
index 0000000000..35a27bb0a6
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/ReverseArrowPiece.cs
@@ -0,0 +1,43 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Audio.Track;
+using osu.Framework.Graphics;
+using osuTK;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.Containers;
+using osu.Game.Skinning;
+
+namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
+{
+ public class ReverseArrowPiece : BeatSyncedContainer
+ {
+ public ReverseArrowPiece()
+ {
+ Divisor = 2;
+ MinimumBeatLength = 200;
+
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Blending = BlendingParameters.Additive;
+
+ Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
+
+ Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.ReverseArrow), _ => new SpriteIcon
+ {
+ RelativeSizeAxes = Axes.Both,
+ Icon = FontAwesome.Solid.ChevronRight,
+ Size = new Vector2(0.35f)
+ })
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ };
+ }
+
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, TrackAmplitudes amplitudes) =>
+ Child.ScaleTo(1.3f).ScaleTo(1f, timingPoint.BeatLength, Easing.Out);
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
index ef7b077480..0dc5c9b4a0 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public Func GetInitialHitAction;
private readonly Slider slider;
- public readonly Drawable FollowCircle;
+ private readonly Drawable followCircle;
private readonly DrawableSlider drawableSlider;
public SliderBall(Slider slider, DrawableSlider drawableSlider = null)
@@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Children = new[]
{
- FollowCircle = new FollowCircleContainer
+ followCircle = new FollowCircleContainer
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
@@ -95,8 +95,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
tracking = value;
- FollowCircle.ScaleTo(tracking ? 2f : 1, 300, Easing.OutQuint);
- FollowCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
+ followCircle.ScaleTo(tracking ? 2.4f : 1f, 300, Easing.OutQuint);
+ followCircle.FadeTo(tracking ? 1f : 0, 300, Easing.OutQuint);
}
}
@@ -149,7 +149,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
// in valid time range
Time.Current >= slider.StartTime && Time.Current < slider.EndTime &&
// in valid position range
- lastScreenSpaceMousePosition.HasValue && FollowCircle.ReceivePositionalInputAt(lastScreenSpaceMousePosition.Value) &&
+ lastScreenSpaceMousePosition.HasValue && followCircle.ReceivePositionalInputAt(lastScreenSpaceMousePosition.Value) &&
// valid action
(actions?.Any(isValidTrackingAction) ?? false);
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
index 8a8668d6af..e24fa865ad 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SnakingSliderBody.cs
@@ -125,7 +125,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private void setRange(double p0, double p1)
{
if (p0 > p1)
- MathHelper.Swap(ref p0, ref p1);
+ (p0, p1) = (p1, p0);
if (SnakedStart == p0 && SnakedEnd == p1) return;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
index c45e98cc76..e3dd2b1b4f 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerDisc.cs
@@ -8,6 +8,7 @@ using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osuTK;
using osuTK.Graphics;
+using osu.Framework.Utils;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
@@ -93,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
base.Update();
- var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
+ var thisAngle = -MathUtils.RadiansToDegrees(MathF.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
bool validAndTracking = tracking && spinner.StartTime <= Time.Current && spinner.EndTime > Time.Current;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs
index 97a7b98c5b..80ab03c45c 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerSpmCounter.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
diff --git a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
index 0ba712a83f..15af141c99 100644
--- a/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/OsuHitObject.cs
@@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.Objects
public double Radius => OBJECT_RADIUS * Scale;
- public readonly Bindable ScaleBindable = new Bindable(1);
+ public readonly Bindable ScaleBindable = new BindableFloat(1);
public float Scale
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index fe65ab78d1..95fb6d9d48 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -18,7 +18,12 @@ namespace osu.Game.Rulesets.Osu.Objects
{
public class Slider : OsuHitObject, IHasCurve
{
- public double EndTime => StartTime + this.SpanCount() * Path.Distance / Velocity;
+ public double EndTime
+ {
+ get => StartTime + this.SpanCount() * Path.Distance / Velocity;
+ set => throw new System.NotSupportedException($"Adjust via {nameof(RepeatCount)} instead"); // can be implemented if/when needed.
+ }
+
public double Duration => EndTime - StartTime;
private readonly Cached endPositionCache = new Cached();
@@ -81,7 +86,7 @@ namespace osu.Game.Rulesets.Osu.Objects
set
{
repeatCount = value;
- endPositionCache.Invalidate();
+ updateNestedPositions();
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Spinner.cs b/osu.Game.Rulesets.Osu/Objects/Spinner.cs
index 2441a1449d..0b8d03d118 100644
--- a/osu.Game.Rulesets.Osu/Objects/Spinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Spinner.cs
@@ -13,8 +13,13 @@ namespace osu.Game.Rulesets.Osu.Objects
{
public class Spinner : OsuHitObject, IHasEndTime
{
- public double EndTime { get; set; }
- public double Duration => EndTime - StartTime;
+ public double EndTime
+ {
+ get => StartTime + Duration;
+ set => Duration = value - StartTime;
+ }
+
+ public double Duration { get; set; }
///
/// Number of spins required to finish the spinner without miss.
diff --git a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs
index 2686ba4fd2..4cb2cd6539 100644
--- a/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs
+++ b/osu.Game.Rulesets.Osu/Replays/OsuAutoGenerator.cs
@@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osuTK;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using System;
diff --git a/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs b/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs
index c6ac1dd346..b42e9ac187 100644
--- a/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Input.StateChanges;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Replays;
using osu.Game.Rulesets.Replays;
using osuTK;
diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs
index d41135ca69..21df49d80b 100644
--- a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/LegacySliderBody.cs
@@ -3,7 +3,7 @@
using System;
using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs
index 266b619334..d6c3f443eb 100644
--- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkinTransformer.cs
@@ -46,17 +46,20 @@ namespace osu.Game.Rulesets.Osu.Skinning
switch (osuComponent.Component)
{
case OsuSkinComponents.FollowPoint:
- return this.GetAnimation(component.LookupName, true, false);
+ return this.GetAnimation(component.LookupName, true, false, true);
case OsuSkinComponents.SliderFollowCircle:
- var followCircle = this.GetAnimation("sliderfollowcircle", true, true);
+ var followCircle = this.GetAnimation("sliderfollowcircle", true, true, true);
if (followCircle != null)
// follow circles are 2x the hitcircle resolution in legacy skins (since they are scaled down from >1x
followCircle.Scale *= 0.5f;
return followCircle;
case OsuSkinComponents.SliderBall:
- var sliderBallContent = this.GetAnimation("sliderb", true, true, "");
+ var sliderBallContent = this.GetAnimation("sliderb", true, true, animationSeparator: "");
+
+ // todo: slider ball has a custom frame delay based on velocity
+ // Math.Max((150 / Velocity) * GameBase.SIXTY_FRAME_TIME, GameBase.SIXTY_FRAME_TIME);
if (sliderBallContent != null)
{
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
index 6433ced624..79b5d1b7f8 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs
@@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize);
autoCursorScale.ValueChanged += _ => calculateScale();
- CursorScale = new Bindable();
+ CursorScale = new BindableFloat();
CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue);
calculateScale();
@@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
return false;
}
- public bool OnReleased(OsuAction action)
+ public void OnReleased(OsuAction action)
{
switch (action)
{
@@ -120,8 +120,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
updateExpandedState();
break;
}
-
- return false;
}
public override bool HandlePositionalInput => true; // OverlayContainer will set this false when we go hidden, but we always want to receive input.
diff --git a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
index 3b18e41f30..abba444c73 100644
--- a/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
+++ b/osu.Game.Rulesets.Osu/UI/OsuResumeOverlay.cs
@@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.UI
{
Add(localCursorContainer = new OsuCursorContainer());
- localCursorScale = new Bindable();
+ localCursorScale = new BindableFloat();
localCursorScale.BindTo(localCursorContainer.CursorScale);
localCursorScale.BindValueChanged(scale => cursorScaleContainer.Scale = new Vector2(scale.NewValue), true);
}
@@ -107,7 +107,9 @@ namespace osu.Game.Rulesets.Osu.UI
return false;
}
- public bool OnReleased(OsuAction action) => false;
+ public void OnReleased(OsuAction action)
+ {
+ }
public void Appear() => Schedule(() =>
{
diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs
index 28f5d4d301..f23fd6d3f9 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TaikoBeatmapConversionTest.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Tests.Beatmaps;
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
index b2c8c7feda..c01eef5252 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoPlayfield.cs
@@ -7,7 +7,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index d728d65bfd..f6054a5d6f 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -2,7 +2,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
index 338fd9e20f..5806c90115 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
@@ -4,7 +4,7 @@
using System;
using System.Linq;
using osu.Framework.Allocation;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK.Graphics;
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
index 4b25ff0ecc..85dfc8d5e0 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableHit.cs
@@ -77,11 +77,12 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
return result;
}
- public override bool OnReleased(TaikoAction action)
+ public override void OnReleased(TaikoAction action)
{
if (action == HitAction)
HitAction = null;
- return base.OnReleased(action);
+
+ base.OnReleased(action);
}
protected override void Update()
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index b9d31ff906..5f892dd2fa 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -77,7 +77,10 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
public Drawable CreateProxiedContent() => proxiedContent.CreateProxy();
public abstract bool OnPressed(TaikoAction action);
- public virtual bool OnReleased(TaikoAction action) => false;
+
+ public virtual void OnReleased(TaikoAction action)
+ {
+ }
public override double LifetimeStart
{
diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
index 8956ca9c19..aacd78f176 100644
--- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs
@@ -18,7 +18,11 @@ namespace osu.Game.Rulesets.Taiko.Objects
///
private const float base_distance = 100;
- public double EndTime => StartTime + Duration;
+ public double EndTime
+ {
+ get => StartTime + Duration;
+ set => Duration = value - StartTime;
+ }
public double Duration { get; set; }
diff --git a/osu.Game.Rulesets.Taiko/Objects/Swell.cs b/osu.Game.Rulesets.Taiko/Objects/Swell.cs
index e60984596d..2f06066a16 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Swell.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Swell.cs
@@ -11,7 +11,11 @@ namespace osu.Game.Rulesets.Taiko.Objects
{
public class Swell : TaikoHitObject, IHasEndTime
{
- public double EndTime => StartTime + Duration;
+ public double EndTime
+ {
+ get => StartTime + Duration;
+ set => Duration = value - StartTime;
+ }
public double Duration { get; set; }
diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs
index 5234ae1f69..d26ccfe867 100644
--- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs
+++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs
@@ -187,7 +187,9 @@ namespace osu.Game.Rulesets.Taiko.UI
return false;
}
- public bool OnReleased(TaikoAction action) => false;
+ public void OnReleased(TaikoAction action)
+ {
+ }
}
}
}
diff --git a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
index 4766411cbd..c1bd73ef05 100644
--- a/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
+++ b/osu.Game.Tests/Beatmaps/IO/ImportBeatmapTest.cs
@@ -5,6 +5,7 @@ using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
@@ -13,7 +14,9 @@ using osu.Game.IPC;
using osu.Framework.Allocation;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.Formats;
using osu.Game.IO;
+using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Tests.Resources;
using SharpCompress.Archives;
using SharpCompress.Archives.Zip;
@@ -552,6 +555,83 @@ namespace osu.Game.Tests.Beatmaps.IO
}
}
+ [Test]
+ public async Task TestUpdateBeatmapInfo()
+ {
+ using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapInfo)))
+ {
+ try
+ {
+ var osu = loadOsu(host);
+ var manager = osu.Dependencies.Get();
+
+ var temp = TestResources.GetTestBeatmapForImport();
+ await osu.Dependencies.Get().Import(temp);
+
+ // Update via the beatmap, not the beatmap info, to ensure correct linking
+ BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
+ Beatmap beatmapToUpdate = (Beatmap)manager.GetWorkingBeatmap(setToUpdate.Beatmaps.First(b => b.RulesetID == 0)).Beatmap;
+ beatmapToUpdate.BeatmapInfo.Version = "updated";
+
+ manager.Update(setToUpdate);
+
+ BeatmapInfo updatedInfo = manager.QueryBeatmap(b => b.ID == beatmapToUpdate.BeatmapInfo.ID);
+ Assert.That(updatedInfo.Version, Is.EqualTo("updated"));
+ }
+ finally
+ {
+ host.Exit();
+ }
+ }
+ }
+
+ [Test]
+ public async Task TestUpdateBeatmapFile()
+ {
+ using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUpdateBeatmapFile)))
+ {
+ try
+ {
+ var osu = loadOsu(host);
+ var manager = osu.Dependencies.Get();
+
+ var temp = TestResources.GetTestBeatmapForImport();
+ await osu.Dependencies.Get().Import(temp);
+
+ BeatmapSetInfo setToUpdate = manager.GetAllUsableBeatmapSets()[0];
+ Beatmap beatmapToUpdate = (Beatmap)manager.GetWorkingBeatmap(setToUpdate.Beatmaps.First(b => b.RulesetID == 0)).Beatmap;
+ BeatmapSetFileInfo fileToUpdate = setToUpdate.Files.First(f => beatmapToUpdate.BeatmapInfo.Path.Contains(f.Filename));
+
+ using (var stream = new MemoryStream())
+ {
+ using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
+ {
+ beatmapToUpdate.HitObjects.Clear();
+ beatmapToUpdate.HitObjects.Add(new HitCircle { StartTime = 5000 });
+
+ new LegacyBeatmapEncoder(beatmapToUpdate).Encode(writer);
+ }
+
+ stream.Seek(0, SeekOrigin.Begin);
+
+ manager.UpdateFile(setToUpdate, fileToUpdate, stream);
+ }
+
+ // Check that the old file reference has been removed
+ Assert.That(manager.QueryBeatmapSet(s => s.ID == setToUpdate.ID).Files.All(f => f.ID != fileToUpdate.ID));
+
+ // Check that the new file is referenced correctly by attempting a retrieval
+ Beatmap updatedBeatmap = (Beatmap)manager.GetWorkingBeatmap(manager.QueryBeatmap(b => b.ID == beatmapToUpdate.BeatmapInfo.ID)).Beatmap;
+ Assert.That(updatedBeatmap.HitObjects.Count, Is.EqualTo(1));
+ Assert.That(updatedBeatmap.HitObjects[0].StartTime, Is.EqualTo(5000));
+ }
+ finally
+ {
+ host.Exit();
+ }
+ }
+ }
+
public static async Task LoadOszIntoOsu(OsuGameBase osu, string path = null, bool virtualTrack = false)
{
var temp = path ?? TestResources.GetTestBeatmapForImport(virtualTrack);
diff --git a/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs b/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs
index 2d336bd19c..3cb5909ba9 100644
--- a/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs
+++ b/osu.Game.Tests/Editor/TestSceneHitObjectComposerDistanceSnapping.cs
@@ -3,8 +3,11 @@
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Framework.Testing;
using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Edit;
@@ -19,12 +22,34 @@ namespace osu.Game.Tests.Editor
private TestHitObjectComposer composer;
[Cached(typeof(EditorBeatmap))]
- private readonly EditorBeatmap editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ [Cached(typeof(IBeatSnapProvider))]
+ private readonly EditorBeatmap editorBeatmap;
+
+ protected override Container Content { get; }
+
+ public TestSceneHitObjectComposerDistanceSnapping()
+ {
+ base.Content.Add(new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ editorBeatmap = new EditorBeatmap(new OsuBeatmap()),
+ Content = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ }
+ },
+ });
+ }
[SetUp]
public void Setup() => Schedule(() =>
{
- Child = composer = new TestHitObjectComposer();
+ Children = new Drawable[]
+ {
+ composer = new TestHitObjectComposer()
+ };
BeatDivisor.Value = 1;
@@ -111,17 +136,19 @@ namespace osu.Game.Tests.Editor
[Test]
public void TestGetSnappedDurationFromDistance()
{
- assertSnappedDuration(50, 0);
+ assertSnappedDuration(0, 0);
+ assertSnappedDuration(50, 1000);
assertSnappedDuration(100, 1000);
- assertSnappedDuration(150, 1000);
+ assertSnappedDuration(150, 2000);
assertSnappedDuration(200, 2000);
- assertSnappedDuration(250, 2000);
+ assertSnappedDuration(250, 3000);
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
+ assertSnappedDuration(0, 0);
assertSnappedDuration(50, 0);
- assertSnappedDuration(100, 0);
- assertSnappedDuration(150, 0);
+ assertSnappedDuration(100, 1000);
+ assertSnappedDuration(150, 1000);
assertSnappedDuration(200, 1000);
assertSnappedDuration(250, 1000);
@@ -132,8 +159,8 @@ namespace osu.Game.Tests.Editor
});
assertSnappedDuration(50, 0);
- assertSnappedDuration(100, 0);
- assertSnappedDuration(150, 0);
+ assertSnappedDuration(100, 500);
+ assertSnappedDuration(150, 500);
assertSnappedDuration(200, 500);
assertSnappedDuration(250, 500);
assertSnappedDuration(400, 1000);
@@ -142,17 +169,17 @@ namespace osu.Game.Tests.Editor
[Test]
public void GetSnappedDistanceFromDistance()
{
- assertSnappedDistance(50, 0);
+ assertSnappedDistance(50, 100);
assertSnappedDistance(100, 100);
- assertSnappedDistance(150, 100);
+ assertSnappedDistance(150, 200);
assertSnappedDistance(200, 200);
- assertSnappedDistance(250, 200);
+ assertSnappedDistance(250, 300);
AddStep("set slider multiplier = 2", () => composer.EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier = 2);
assertSnappedDistance(50, 0);
- assertSnappedDistance(100, 0);
- assertSnappedDistance(150, 0);
+ assertSnappedDistance(100, 200);
+ assertSnappedDistance(150, 200);
assertSnappedDistance(200, 200);
assertSnappedDistance(250, 200);
@@ -163,8 +190,8 @@ namespace osu.Game.Tests.Editor
});
assertSnappedDistance(50, 0);
- assertSnappedDistance(100, 0);
- assertSnappedDistance(150, 0);
+ assertSnappedDistance(100, 200);
+ assertSnappedDistance(150, 200);
assertSnappedDistance(200, 200);
assertSnappedDistance(250, 200);
assertSnappedDistance(400, 400);
diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
index eec52669ff..244e37f017 100644
--- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Testing;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
index c6d1f9da29..17dc27543d 100644
--- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
@@ -126,10 +126,10 @@ namespace osu.Game.Tests.Gameplay
{
switch (lookup)
{
- case GlobalSkinConfiguration global:
+ case GlobalSkinColours global:
switch (global)
{
- case GlobalSkinConfiguration.ComboColours:
+ case GlobalSkinColours.ComboColours:
return SkinUtils.As(new Bindable>(ComboColours));
}
diff --git a/osu.Game.Tests/Online/TestAPIModSerialization.cs b/osu.Game.Tests/Online/TestAPIModSerialization.cs
new file mode 100644
index 0000000000..d9318aa822
--- /dev/null
+++ b/osu.Game.Tests/Online/TestAPIModSerialization.cs
@@ -0,0 +1,82 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using NUnit.Framework;
+using osu.Framework.Bindables;
+using osu.Game.Beatmaps;
+using osu.Game.Configuration;
+using osu.Game.Online.API;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Difficulty;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.UI;
+
+namespace osu.Game.Tests.Online
+{
+ [TestFixture]
+ public class TestAPIModSerialization
+ {
+ [Test]
+ public void TestAcronymIsPreserved()
+ {
+ var apiMod = new APIMod(new TestMod());
+
+ var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(apiMod));
+
+ Assert.That(deserialized.Acronym, Is.EqualTo(apiMod.Acronym));
+ }
+
+ [Test]
+ public void TestRawSettingIsPreserved()
+ {
+ var apiMod = new APIMod(new TestMod { TestSetting = { Value = 2 } });
+
+ var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(apiMod));
+
+ Assert.That(deserialized.Settings, Contains.Key("test_setting").With.ContainValue(2.0));
+ }
+
+ [Test]
+ public void TestConvertedModHasCorrectSetting()
+ {
+ var apiMod = new APIMod(new TestMod { TestSetting = { Value = 2 } });
+
+ var deserialized = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(apiMod));
+ var converted = (TestMod)deserialized.ToMod(new TestRuleset());
+
+ Assert.That(converted.TestSetting.Value, Is.EqualTo(2));
+ }
+
+ private class TestRuleset : Ruleset
+ {
+ public override IEnumerable GetModsFor(ModType type) => new[] { new TestMod() };
+
+ public override DrawableRuleset CreateDrawableRulesetWith(IBeatmap beatmap, IReadOnlyList mods = null) => throw new System.NotImplementedException();
+
+ public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => throw new System.NotImplementedException();
+
+ public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => throw new System.NotImplementedException();
+
+ public override string Description { get; } = string.Empty;
+ public override string ShortName { get; } = string.Empty;
+ }
+
+ private class TestMod : Mod
+ {
+ public override string Name => "Test Mod";
+ public override string Acronym => "TM";
+ public override double ScoreMultiplier => 1;
+
+ [SettingSource("Test")]
+ public BindableNumber TestSetting { get; } = new BindableDouble
+ {
+ MinValue = 0,
+ MaxValue = 10,
+ Default = 5,
+ Precision = 0.01,
+ };
+ }
+ }
+}
diff --git a/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs
index d7f709dc03..a6e8622b6f 100644
--- a/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs
+++ b/osu.Game.Tests/ScrollAlgorithms/ConstantScrollTest.cs
@@ -18,12 +18,21 @@ namespace osu.Game.Tests.ScrollAlgorithms
}
[Test]
- public void TestDisplayStartTime()
+ public void TestPointDisplayStartTime()
{
- Assert.AreEqual(-8000, algorithm.GetDisplayStartTime(2000, 10000));
- Assert.AreEqual(-3000, algorithm.GetDisplayStartTime(2000, 5000));
- Assert.AreEqual(2000, algorithm.GetDisplayStartTime(7000, 5000));
- Assert.AreEqual(7000, algorithm.GetDisplayStartTime(17000, 10000));
+ Assert.AreEqual(-8000, algorithm.GetDisplayStartTime(2000, 0, 10000, 1));
+ Assert.AreEqual(-3000, algorithm.GetDisplayStartTime(2000, 0, 5000, 1));
+ Assert.AreEqual(2000, algorithm.GetDisplayStartTime(7000, 0, 5000, 1));
+ Assert.AreEqual(7000, algorithm.GetDisplayStartTime(17000, 0, 10000, 1));
+ }
+
+ [Test]
+ public void TestObjectDisplayStartTime()
+ {
+ Assert.AreEqual(900, algorithm.GetDisplayStartTime(2000, 50, 1000, 500)); // 2000 - (1 + 50 / 500) * 1000
+ Assert.AreEqual(8900, algorithm.GetDisplayStartTime(10000, 50, 1000, 500)); // 10000 - (1 + 50 / 500) * 1000
+ Assert.AreEqual(13500, algorithm.GetDisplayStartTime(15000, 250, 1000, 500)); // 15000 - (1 + 250 / 500) * 1000
+ Assert.AreEqual(19000, algorithm.GetDisplayStartTime(25000, 100, 5000, 500)); // 25000 - (1 + 100 / 500) * 5000
}
[Test]
diff --git a/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs b/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs
index 106aa88be3..1429d22c1a 100644
--- a/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs
+++ b/osu.Game.Tests/ScrollAlgorithms/OverlappingScrollTest.cs
@@ -27,11 +27,22 @@ namespace osu.Game.Tests.ScrollAlgorithms
}
[Test]
- public void TestDisplayStartTime()
+ public void TestPointDisplayStartTime()
{
- Assert.AreEqual(1000, algorithm.GetDisplayStartTime(2000, 1000)); // Like constant
- Assert.AreEqual(10000, algorithm.GetDisplayStartTime(10500, 1000)); // 10500 - (1000 * 0.5)
- Assert.AreEqual(20000, algorithm.GetDisplayStartTime(22000, 1000)); // 23000 - (1000 / 0.5)
+ Assert.AreEqual(1000, algorithm.GetDisplayStartTime(2000, 0, 1000, 1)); // Like constant
+ Assert.AreEqual(10000, algorithm.GetDisplayStartTime(10500, 0, 1000, 1)); // 10500 - (1000 * 0.5)
+ Assert.AreEqual(20000, algorithm.GetDisplayStartTime(22000, 0, 1000, 1)); // 23000 - (1000 / 0.5)
+ }
+
+ [Test]
+ public void TestObjectDisplayStartTime()
+ {
+ Assert.AreEqual(900, algorithm.GetDisplayStartTime(2000, 50, 1000, 500)); // 2000 - (1 + 50 / 500) * 1000 / 1
+ Assert.AreEqual(9450, algorithm.GetDisplayStartTime(10000, 50, 1000, 500)); // 10000 - (1 + 50 / 500) * 1000 / 2
+ Assert.AreEqual(14250, algorithm.GetDisplayStartTime(15000, 250, 1000, 500)); // 15000 - (1 + 250 / 500) * 1000 / 2
+ Assert.AreEqual(16500, algorithm.GetDisplayStartTime(18000, 250, 2000, 500)); // 18000 - (1 + 250 / 500) * 2000 / 2
+ Assert.AreEqual(17800, algorithm.GetDisplayStartTime(20000, 50, 1000, 500)); // 20000 - (1 + 50 / 500) * 1000 / 0.5
+ Assert.AreEqual(19800, algorithm.GetDisplayStartTime(22000, 50, 1000, 500)); // 22000 - (1 + 50 / 500) * 1000 / 0.5
}
[Test]
diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
index ed54cc982d..35313ee858 100644
--- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
+++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs
@@ -95,7 +95,7 @@ namespace osu.Game.Tests.Skins
[Test]
public void TestGlobalLookup()
{
- AddAssert("Check combo colours", () => requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.Count > 0);
+ AddAssert("Check combo colours", () => requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.Count > 0);
}
[Test]
@@ -121,7 +121,7 @@ namespace osu.Game.Tests.Skins
public void TestEmptyComboColours()
{
AddAssert("Check retrieved combo colours is skin default colours", () =>
- requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(SkinConfiguration.DefaultComboColours) ?? false);
+ requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.SequenceEqual(SkinConfiguration.DefaultComboColours) ?? false);
}
[Test]
@@ -136,7 +136,7 @@ namespace osu.Game.Tests.Skins
AddStep("Disallow default colours fallback in source2", () => source2.Configuration.AllowDefaultComboColoursFallback = false);
AddAssert("Check retrieved combo colours from source1", () =>
- requester.GetConfig>(GlobalSkinConfiguration.ComboColours)?.Value?.SequenceEqual(source1.Configuration.ComboColours) ?? false);
+ requester.GetConfig>(GlobalSkinColours.ComboColours)?.Value?.SequenceEqual(source1.Configuration.ComboColours) ?? false);
}
[Test]
diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
index 589ec7e8aa..6d014ca1ca 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -68,10 +68,10 @@ namespace osu.Game.Tests.Visual.Background
[SetUp]
public virtual void SetUp() => Schedule(() =>
{
- Child = new OsuScreenStack(songSelect = new DummySongSelect())
- {
- RelativeSizeAxes = Axes.Both
- };
+ var stack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
+ Child = stack;
+
+ stack.Push(songSelect = new DummySongSelect());
});
///
@@ -277,7 +277,7 @@ namespace osu.Game.Tests.Visual.Background
private void setupUserSettings()
{
- AddUntilStep("Song select has selection", () => songSelect.Carousel.SelectedBeatmap != null);
+ AddUntilStep("Song select has selection", () => songSelect.Carousel?.SelectedBeatmap != null);
AddStep("Set default user settings", () =>
{
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new OsuModNoFail() }).ToArray();
@@ -302,8 +302,8 @@ namespace osu.Game.Tests.Visual.Background
}
public readonly Bindable DimEnabled = new Bindable();
- public readonly Bindable DimLevel = new Bindable();
- public readonly Bindable BlurLevel = new Bindable();
+ public readonly Bindable DimLevel = new BindableDouble();
+ public readonly Bindable BlurLevel = new BindableDouble();
public new BeatmapCarousel Carousel => base.Carousel;
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs
index 3562689482..a8830824c0 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneComposeScreen.cs
@@ -3,6 +3,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
+using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Screens.Edit;
@@ -14,6 +15,7 @@ namespace osu.Game.Tests.Visual.Editor
public class TestSceneComposeScreen : EditorClockTestScene
{
[Cached(typeof(EditorBeatmap))]
+ [Cached(typeof(IBeatSnapProvider))]
private readonly EditorBeatmap editorBeatmap =
new EditorBeatmap(new OsuBeatmap
{
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
index 847d168e51..f49256a633 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneDistanceSnapGrid.cs
@@ -85,64 +85,64 @@ namespace osu.Game.Tests.Visual.Editor
{
}
- protected override void CreateContent(Vector2 startPosition)
+ protected override void CreateContent()
{
AddInternal(new Circle
{
Origin = Anchor.Centre,
Size = new Vector2(5),
- Position = startPosition
+ Position = StartPosition
});
- int beatIndex = 0;
+ int indexFromPlacement = 0;
- for (float s = startPosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
+ for (float s = StartPosition.X + DistanceSpacing; s <= DrawWidth && indexFromPlacement < MaxIntervals; s += DistanceSpacing, indexFromPlacement++)
{
AddInternal(new Circle
{
Origin = Anchor.Centre,
Size = new Vector2(5, 10),
- Position = new Vector2(s, startPosition.Y),
- Colour = GetColourForBeatIndex(beatIndex)
+ Position = new Vector2(s, StartPosition.Y),
+ Colour = GetColourForIndexFromPlacement(indexFromPlacement)
});
}
- beatIndex = 0;
+ indexFromPlacement = 0;
- for (float s = startPosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
+ for (float s = StartPosition.X - DistanceSpacing; s >= 0 && indexFromPlacement < MaxIntervals; s -= DistanceSpacing, indexFromPlacement++)
{
AddInternal(new Circle
{
Origin = Anchor.Centre,
Size = new Vector2(5, 10),
- Position = new Vector2(s, startPosition.Y),
- Colour = GetColourForBeatIndex(beatIndex)
+ Position = new Vector2(s, StartPosition.Y),
+ Colour = GetColourForIndexFromPlacement(indexFromPlacement)
});
}
- beatIndex = 0;
+ indexFromPlacement = 0;
- for (float s = startPosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
+ for (float s = StartPosition.Y + DistanceSpacing; s <= DrawHeight && indexFromPlacement < MaxIntervals; s += DistanceSpacing, indexFromPlacement++)
{
AddInternal(new Circle
{
Origin = Anchor.Centre,
Size = new Vector2(10, 5),
- Position = new Vector2(startPosition.X, s),
- Colour = GetColourForBeatIndex(beatIndex)
+ Position = new Vector2(StartPosition.X, s),
+ Colour = GetColourForIndexFromPlacement(indexFromPlacement)
});
}
- beatIndex = 0;
+ indexFromPlacement = 0;
- for (float s = startPosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
+ for (float s = StartPosition.Y - DistanceSpacing; s >= 0 && indexFromPlacement < MaxIntervals; s -= DistanceSpacing, indexFromPlacement++)
{
AddInternal(new Circle
{
Origin = Anchor.Centre,
Size = new Vector2(10, 5),
- Position = new Vector2(startPosition.X, s),
- Colour = GetColourForBeatIndex(beatIndex)
+ Position = new Vector2(StartPosition.X, s),
+ Colour = GetColourForIndexFromPlacement(indexFromPlacement)
});
}
}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs
index c001c83877..e41c2427fb 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneHitObjectComposer.cs
@@ -66,6 +66,7 @@ namespace osu.Game.Tests.Visual.Editor
Dependencies.CacheAs(clock);
Dependencies.CacheAs(clock);
Dependencies.CacheAs(editorBeatmap);
+ Dependencies.CacheAs(editorBeatmap);
Child = new OsuHitObjectComposer(new OsuRuleset());
}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneTimelineBlueprintContainer.cs b/osu.Game.Tests/Visual/Editor/TestSceneTimelineBlueprintContainer.cs
new file mode 100644
index 0000000000..4d8f877575
--- /dev/null
+++ b/osu.Game.Tests/Visual/Editor/TestSceneTimelineBlueprintContainer.cs
@@ -0,0 +1,28 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Game.Screens.Edit.Compose.Components.Timeline;
+
+namespace osu.Game.Tests.Visual.Editor
+{
+ [TestFixture]
+ public class TestSceneTimelineBlueprintContainer : TimelineTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(TimelineHitObjectBlueprint),
+ };
+
+ public override Drawable CreateTestComponent() => new TimelineBlueprintContainer();
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ Clock.Seek(10000);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneTimelineTickDisplay.cs b/osu.Game.Tests/Visual/Editor/TestSceneTimelineTickDisplay.cs
new file mode 100644
index 0000000000..43a3cd6122
--- /dev/null
+++ b/osu.Game.Tests/Visual/Editor/TestSceneTimelineTickDisplay.cs
@@ -0,0 +1,32 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Screens.Edit.Compose.Components;
+using osu.Game.Screens.Edit.Compose.Components.Timeline;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Editor
+{
+ [TestFixture]
+ public class TestSceneTimelineTickDisplay : TimelineTestScene
+ {
+ public override Drawable CreateTestComponent() => new TimelineTickDisplay();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ BeatDivisor.Value = 4;
+
+ Add(new BeatDivisorControl(BeatDivisor)
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Margin = new MarginPadding(30),
+ Size = new Vector2(90)
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
index adfed9a299..ae09a7fa47 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneTimingScreen.cs
@@ -27,7 +27,12 @@ namespace osu.Game.Tests.Visual.Editor
};
[Cached(typeof(EditorBeatmap))]
- private readonly EditorBeatmap editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ private readonly EditorBeatmap editorBeatmap;
+
+ public TestSceneTimingScreen()
+ {
+ editorBeatmap = new EditorBeatmap(new OsuBeatmap());
+ }
[BackgroundDependencyLoader]
private void load()
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneZoomableScrollContainer.cs b/osu.Game.Tests/Visual/Editor/TestSceneZoomableScrollContainer.cs
index da8702209c..fd248abbc9 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneZoomableScrollContainer.cs
+++ b/osu.Game.Tests/Visual/Editor/TestSceneZoomableScrollContainer.cs
@@ -7,7 +7,7 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Graphics.Cursor;
diff --git a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs b/osu.Game.Tests/Visual/Editor/TimelineTestScene.cs
similarity index 83%
rename from osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
rename to osu.Game.Tests/Visual/Editor/TimelineTestScene.cs
index 29575cb42e..7081eb3af5 100644
--- a/osu.Game.Tests/Visual/Editor/TestSceneEditorComposeTimeline.cs
+++ b/osu.Game.Tests/Visual/Editor/TimelineTestScene.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
@@ -13,7 +12,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Graphics.UserInterface;
-using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osuTK;
@@ -21,27 +20,33 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor
{
- [TestFixture]
- public class TestSceneEditorComposeTimeline : EditorClockTestScene
+ public abstract class TimelineTestScene : EditorClockTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
typeof(TimelineArea),
- typeof(TimelineHitObjectDisplay),
typeof(Timeline),
typeof(TimelineButton),
typeof(CentreMarker)
};
+ protected TimelineArea TimelineArea { get; private set; }
+
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
Beatmap.Value = new WaveformTestBeatmap(audio);
- var editorBeatmap = new EditorBeatmap((Beatmap)Beatmap.Value.Beatmap);
+ var playable = Beatmap.Value.GetPlayableBeatmap(Beatmap.Value.BeatmapInfo.Ruleset);
- Children = new Drawable[]
+ var editorBeatmap = new EditorBeatmap(playable);
+
+ Dependencies.Cache(editorBeatmap);
+ Dependencies.CacheAs(editorBeatmap);
+
+ AddRange(new Drawable[]
{
+ editorBeatmap,
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
@@ -53,17 +58,19 @@ namespace osu.Game.Tests.Visual.Editor
new AudioVisualiser(),
}
},
- new TimelineArea
+ TimelineArea = new TimelineArea
{
- Child = new TimelineHitObjectDisplay(editorBeatmap),
+ Child = CreateTestComponent(),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
- Size = new Vector2(0.8f, 100)
+ Size = new Vector2(0.8f, 100),
}
- };
+ });
}
+ public abstract Drawable CreateTestComponent();
+
private class AudioVisualiser : CompositeDrawable
{
private readonly Drawable marker;
diff --git a/osu.Game/Tests/Visual/AllPlayersTestScene.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs
similarity index 59%
rename from osu.Game/Tests/Visual/AllPlayersTestScene.cs
rename to osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs
index dd65c8c382..83a7b896d2 100644
--- a/osu.Game/Tests/Visual/AllPlayersTestScene.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs
@@ -2,49 +2,66 @@
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
+using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Screens;
using osu.Game.Configuration;
using osu.Game.Rulesets;
+using osu.Game.Rulesets.Catch;
+using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Taiko;
using osu.Game.Screens.Play;
-namespace osu.Game.Tests.Visual
+namespace osu.Game.Tests.Visual.Gameplay
{
///
/// A base class which runs test for all available rulesets.
/// Steps to be run for each ruleset should be added via .
///
- public abstract class AllPlayersTestScene : RateAdjustedBeatmapTestScene
+ public abstract class TestSceneAllRulesetPlayers : RateAdjustedBeatmapTestScene
{
protected Player Player;
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
- foreach (var r in rulesets.AvailableRulesets)
- {
- Player p = null;
- AddStep(r.Name, () => p = loadPlayerFor(r));
- AddUntilStep("player loaded", () =>
- {
- if (p?.IsLoaded == true)
- {
- p = null;
- return true;
- }
-
- return false;
- });
-
- AddCheckSteps();
- }
-
OsuConfigManager manager;
Dependencies.Cache(manager = new OsuConfigManager(LocalStorage));
manager.GetBindable(OsuSetting.DimLevel).Value = 1.0;
}
+ [Test]
+ public void TestOsu() => runForRuleset(new OsuRuleset().RulesetInfo);
+
+ [Test]
+ public void TestTaiko() => runForRuleset(new TaikoRuleset().RulesetInfo);
+
+ [Test]
+ public void TestCatch() => runForRuleset(new CatchRuleset().RulesetInfo);
+
+ [Test]
+ public void TestMania() => runForRuleset(new ManiaRuleset().RulesetInfo);
+
+ private void runForRuleset(RulesetInfo ruleset)
+ {
+ Player p = null;
+ AddStep($"load {ruleset.Name} player", () => p = loadPlayerFor(ruleset));
+ AddUntilStep("player loaded", () =>
+ {
+ if (p?.IsLoaded == true)
+ {
+ p = null;
+ return true;
+ }
+
+ return false;
+ });
+
+ AddCheckSteps();
+ }
+
protected abstract void AddCheckSteps();
private Player loadPlayerFor(RulesetInfo rulesetInfo)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 069b965d9b..4daab8d137 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -12,7 +12,7 @@ using osu.Game.Storyboards;
namespace osu.Game.Tests.Visual.Gameplay
{
[Description("Player instantiated with an autoplay mod.")]
- public class TestSceneAutoplay : AllPlayersTestScene
+ public class TestSceneAutoplay : TestSceneAllRulesetPlayers
{
private ClockBackedTestWorkingBeatmap.TrackVirtualManual track;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
index 36235a4418..46f62b9541 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
@@ -10,7 +10,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
index 81050b1637..de257c9e53 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailAnimation.cs
@@ -10,7 +10,7 @@ using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay
{
- public class TestSceneFailAnimation : AllPlayersTestScene
+ public class TestSceneFailAnimation : TestSceneAllRulesetPlayers
{
protected override Player CreatePlayer(Ruleset ruleset)
{
@@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(AllPlayersTestScene),
+ typeof(TestSceneAllRulesetPlayers),
typeof(TestPlayer),
typeof(Player),
};
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs
index 2045072c79..d80efb2c6e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneFailJudgement.cs
@@ -10,7 +10,7 @@ using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay
{
- public class TestSceneFailJudgement : AllPlayersTestScene
+ public class TestSceneFailJudgement : TestSceneAllRulesetPlayers
{
protected override Player CreatePlayer(Ruleset ruleset)
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
index 5336c720a1..78c3b22fb9 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
@@ -7,7 +7,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index ee58219cd3..fc03dc6ed3 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -2,12 +2,16 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Play;
+using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
@@ -15,7 +19,9 @@ namespace osu.Game.Tests.Visual.Gameplay
{
private HUDOverlay hudOverlay;
- private Drawable hideTarget => hudOverlay.KeyCounter; // best way of checking hideTargets without exposing.
+ // best way to check without exposing.
+ private Drawable hideTarget => hudOverlay.KeyCounter;
+ private FillFlowContainer keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType>().First();
[Resolved]
private OsuConfigManager config { get; set; }
@@ -28,6 +34,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("showhud is set", () => hudOverlay.ShowHud.Value);
AddAssert("hidetarget is visible", () => hideTarget.IsPresent);
+ AddAssert("key counter flow is visible", () => keyCounterFlow.IsPresent);
AddAssert("pause button is visible", () => hudOverlay.HoldToQuit.IsPresent);
}
@@ -50,6 +57,9 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
AddAssert("pause button is still visible", () => hudOverlay.HoldToQuit.IsPresent);
+
+ // Key counter flow container should not be affected by this, only the key counter display will be hidden as checked above.
+ AddAssert("key counter flow not affected", () => keyCounterFlow.IsPresent);
}
[Test]
@@ -68,12 +78,40 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("config unchanged", () => originalConfigValue == config.Get(OsuSetting.ShowInterface));
}
+ [Test]
+ public void TestChangeHUDVisibilityOnHiddenKeyCounter()
+ {
+ bool keyCounterVisibleValue = false;
+
+ createNew();
+ AddStep("save keycounter visible value", () => keyCounterVisibleValue = config.Get(OsuSetting.KeyOverlay));
+
+ AddStep("set keycounter visible false", () =>
+ {
+ config.Set(OsuSetting.KeyOverlay, false);
+ hudOverlay.KeyCounter.AlwaysVisible.Value = false;
+ });
+
+ AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false);
+ AddUntilStep("hidetarget is hidden", () => !hideTarget.IsPresent);
+ AddAssert("key counters hidden", () => !keyCounterFlow.IsPresent);
+
+ AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true);
+ AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
+ AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
+
+ AddStep("return value", () => config.Set(OsuSetting.KeyOverlay, keyCounterVisibleValue));
+ }
+
private void createNew(Action action = null)
{
AddStep("create overlay", () =>
{
Child = hudOverlay = new HUDOverlay(null, null, null, Array.Empty());
+ // Add any key just to display the key counter visually.
+ hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+
action?.Invoke(hudOverlay);
});
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
similarity index 74%
rename from osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
rename to osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
index e3688c276f..8904b54b0d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
@@ -6,7 +6,7 @@ using osu.Game.Rulesets.Objects;
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Judgements;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -19,18 +19,22 @@ using osu.Game.Screens.Play.HUD.HitErrorMeters;
namespace osu.Game.Tests.Visual.Gameplay
{
- public class TestSceneBarHitErrorMeter : OsuTestScene
+ public class TestSceneHitErrorMeter : OsuTestScene
{
public override IReadOnlyList RequiredTypes => new[]
{
typeof(HitErrorMeter),
+ typeof(BarHitErrorMeter),
+ typeof(ColourHitErrorMeter)
};
- private HitErrorMeter meter;
- private HitErrorMeter meter2;
+ private BarHitErrorMeter barMeter;
+ private BarHitErrorMeter barMeter2;
+ private ColourHitErrorMeter colourMeter;
+ private ColourHitErrorMeter colourMeter2;
private HitWindows hitWindows;
- public TestSceneBarHitErrorMeter()
+ public TestSceneHitErrorMeter()
{
recreateDisplay(new OsuHitWindows(), 5);
@@ -91,17 +95,31 @@ namespace osu.Game.Tests.Visual.Gameplay
}
});
- Add(meter = new BarHitErrorMeter(hitWindows, true)
+ Add(barMeter = new BarHitErrorMeter(hitWindows, true)
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
});
- Add(meter2 = new BarHitErrorMeter(hitWindows, false)
+ Add(barMeter2 = new BarHitErrorMeter(hitWindows, false)
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
});
+
+ Add(colourMeter = new ColourHitErrorMeter(hitWindows)
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Margin = new MarginPadding { Right = 50 }
+ });
+
+ Add(colourMeter2 = new ColourHitErrorMeter(hitWindows)
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Margin = new MarginPadding { Left = 50 }
+ });
}
private void newJudgement(double offset = 0)
@@ -112,8 +130,10 @@ namespace osu.Game.Tests.Visual.Gameplay
Type = HitResult.Perfect,
};
- meter.OnNewJudgement(judgement);
- meter2.OnNewJudgement(judgement);
+ barMeter.OnNewJudgement(judgement);
+ barMeter2.OnNewJudgement(judgement);
+ colourMeter.OnNewJudgement(judgement);
+ colourMeter2.OnNewJudgement(judgement);
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index ad747e88e1..e7b3e007fc 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Screens.Play;
using osuTK.Input;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
index 0150c6ea74..563d6be0da 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneLeadIn.cs
@@ -5,7 +5,7 @@ using System.Diagnostics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
index 1a83e35e4f..ad5bab4681 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
@@ -36,6 +36,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public override void SetUpSteps()
{
base.SetUpSteps();
+
AddStep("resume player", () => Player.GameplayClockContainer.Start());
confirmClockRunning(true);
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index f68f4b8b83..33ecbed62e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
@@ -12,7 +12,7 @@ using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Screens;
using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
@@ -146,6 +146,18 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("player mods applied", () => playerMod2.Applied);
}
+ [Test]
+ public void TestModDisplayChanges()
+ {
+ var testMod = new TestMod();
+
+ AddStep("load player", () => ResetPlayer(true));
+
+ AddUntilStep("wait for loader to become current", () => loader.IsCurrentScreen());
+ AddStep("set test mod in loader", () => loader.Mods.Value = new[] { testMod });
+ AddAssert("test mod is displayed", () => (TestMod)loader.DisplayedMods.Single() == testMod);
+ }
+
[Test]
public void TestMutedNotificationMasterVolume() => addVolumeSteps("master volume", () => audioManager.Volume.Value = 0, null, () => audioManager.Volume.IsDefault);
@@ -195,9 +207,11 @@ namespace osu.Game.Tests.Visual.Gameplay
{
RelativeSizeAxes = Axes.Both;
+ OsuScreenStack stack;
+
InternalChildren = new Drawable[]
{
- new OsuScreenStack(screen)
+ stack = new OsuScreenStack
{
RelativeSizeAxes = Axes.Both,
},
@@ -212,6 +226,8 @@ namespace osu.Game.Tests.Visual.Gameplay
Origin = Anchor.TopLeft,
}
};
+
+ stack.Push(screen);
}
}
@@ -221,6 +237,8 @@ namespace osu.Game.Tests.Visual.Gameplay
public new Task DisposalTask => base.DisposalTask;
+ public IReadOnlyList DisplayedMods => MetadataInfo.Mods.Value;
+
public TestPlayerLoader(Func createPlayer)
: base(createPlayer)
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs
index 4d701f56a9..8f767659c6 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerReferenceLeaking.cs
@@ -10,7 +10,7 @@ using osu.Game.Storyboards;
namespace osu.Game.Tests.Visual.Gameplay
{
- public class TestScenePlayerReferenceLeaking : AllPlayersTestScene
+ public class TestScenePlayerReferenceLeaking : TestSceneAllRulesetPlayers
{
private readonly WeakList workingWeakReferences = new WeakList();
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
index 36335bc54a..e82722e7a2 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
@@ -13,7 +13,7 @@ using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay
{
[Description("Player instantiated with a replay.")]
- public class TestSceneReplay : AllPlayersTestScene
+ public class TestSceneReplay : TestSceneAllRulesetPlayers
{
protected override Player CreatePlayer(Ruleset ruleset)
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs
index 7790126db5..2b7a32ba17 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneResults.cs
@@ -75,10 +75,16 @@ namespace osu.Game.Tests.Visual.Gameplay
public void ResultsWithoutPlayer()
{
TestSoloResults screen = null;
+ OsuScreenStack stack;
- AddStep("load results", () => Child = new OsuScreenStack(screen = createResultsScreen())
+ AddStep("load results", () =>
{
- RelativeSizeAxes = Axes.Both
+ Child = stack = new OsuScreenStack
+ {
+ RelativeSizeAxes = Axes.Both
+ };
+
+ stack.Push(screen = createResultsScreen());
});
AddUntilStep("wait for loaded", () => screen.IsLoaded);
AddAssert("retry overlay not present", () => screen.RetryOverlay == null);
@@ -102,11 +108,14 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestResultsContainer(IScreen screen)
{
RelativeSizeAxes = Axes.Both;
+ OsuScreenStack stack;
- InternalChild = new OsuScreenStack(screen)
+ InternalChild = stack = new OsuScreenStack
{
RelativeSizeAxes = Axes.Both,
};
+
+ stack.Push(screen);
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs
index 080a287b48..ffd6f55b53 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScoreCounter.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play.HUD;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs
index 8629522dc2..d03716db2e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneScrollingHitObjects.cs
@@ -11,6 +11,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading;
+using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
@@ -19,6 +20,7 @@ using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osuTK;
+using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Gameplay
{
@@ -30,7 +32,8 @@ namespace osu.Game.Tests.Visual.Gameplay
[Cached(typeof(IReadOnlyList))]
private IReadOnlyList mods { get; set; } = Array.Empty();
- private const int spawn_interval = 5000;
+ private const int time_range = 5000;
+ private const int spawn_rate = time_range / 10;
private readonly ScrollingTestContainer[] scrollContainers = new ScrollingTestContainer[4];
private readonly TestPlayfield[] playfields = new TestPlayfield[4];
@@ -50,13 +53,13 @@ namespace osu.Game.Tests.Visual.Gameplay
{
RelativeSizeAxes = Axes.Both,
Child = playfields[0] = new TestPlayfield(),
- TimeRange = spawn_interval
+ TimeRange = time_range
},
scrollContainers[1] = new ScrollingTestContainer(ScrollingDirection.Down)
{
RelativeSizeAxes = Axes.Both,
Child = playfields[1] = new TestPlayfield(),
- TimeRange = spawn_interval
+ TimeRange = time_range
},
},
new Drawable[]
@@ -65,13 +68,13 @@ namespace osu.Game.Tests.Visual.Gameplay
{
RelativeSizeAxes = Axes.Both,
Child = playfields[2] = new TestPlayfield(),
- TimeRange = spawn_interval
+ TimeRange = time_range
},
scrollContainers[3] = new ScrollingTestContainer(ScrollingDirection.Right)
{
RelativeSizeAxes = Axes.Both,
Child = playfields[3] = new TestPlayfield(),
- TimeRange = spawn_interval
+ TimeRange = time_range
}
}
}
@@ -84,31 +87,55 @@ namespace osu.Game.Tests.Visual.Gameplay
{
scrollContainers.ForEach(c => c.ControlPoints.Add(new MultiplierControlPoint(0)));
- for (int i = 0; i <= spawn_interval; i += 1000)
+ for (int i = spawn_rate / 2; i <= time_range; i += spawn_rate)
addHitObject(Time.Current + i);
hitObjectSpawnDelegate?.Cancel();
- hitObjectSpawnDelegate = Scheduler.AddDelayed(() => addHitObject(Time.Current + spawn_interval), 1000, true);
+ hitObjectSpawnDelegate = Scheduler.AddDelayed(() => addHitObject(Time.Current + time_range), spawn_rate, true);
}
+ private IList testControlPoints => new List
+ {
+ new MultiplierControlPoint(time_range) { DifficultyPoint = { SpeedMultiplier = 1.25 } },
+ new MultiplierControlPoint(1.5 * time_range) { DifficultyPoint = { SpeedMultiplier = 1 } },
+ new MultiplierControlPoint(2 * time_range) { DifficultyPoint = { SpeedMultiplier = 1.5 } }
+ };
+
[Test]
public void TestScrollAlgorithms()
{
- AddStep("Constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant));
- AddStep("Overlapping scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Overlapping));
- AddStep("Sequential scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Sequential));
+ AddStep("constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant));
+ AddStep("overlapping scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Overlapping));
+ AddStep("sequential scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Sequential));
- AddSliderStep("Time range", 100, 10000, spawn_interval, v => scrollContainers.Where(c => c != null).ForEach(c => c.TimeRange = v));
- AddStep("Add control point", () => addControlPoint(Time.Current + spawn_interval));
+ AddSliderStep("time range", 100, 10000, time_range, v => scrollContainers.Where(c => c != null).ForEach(c => c.TimeRange = v));
+
+ AddStep("add control points", () => addControlPoints(testControlPoints, Time.Current));
}
[Test]
- public void TestScrollLifetime()
+ public void TestConstantScrollLifetime()
{
- AddStep("Set constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant));
+ AddStep("set constant scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Constant));
// scroll container time range must be less than the rate of spawning hitobjects
// otherwise the hitobjects will spawn already partly visible on screen and look wrong
- AddStep("Set time range", () => scrollContainers.ForEach(c => c.TimeRange = spawn_interval / 2.0));
+ AddStep("set time range", () => scrollContainers.ForEach(c => c.TimeRange = time_range / 2.0));
+ }
+
+ [Test]
+ public void TestSequentialScrollLifetime()
+ {
+ AddStep("set sequential scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Sequential));
+ AddStep("set time range", () => scrollContainers.ForEach(c => c.TimeRange = time_range / 2.0));
+ AddStep("add control points", () => addControlPoints(testControlPoints, Time.Current));
+ }
+
+ [Test]
+ public void TestOverlappingScrollLifetime()
+ {
+ AddStep("set overlapping scroll", () => setScrollAlgorithm(ScrollVisualisationMethod.Overlapping));
+ AddStep("set time range", () => scrollContainers.ForEach(c => c.TimeRange = time_range / 2.0));
+ AddStep("add control points", () => addControlPoints(testControlPoints, Time.Current));
}
private void addHitObject(double time)
@@ -122,28 +149,27 @@ namespace osu.Game.Tests.Visual.Gameplay
});
}
- private void addControlPoint(double time)
+ private TestDrawableControlPoint createDrawablePoint(TestPlayfield playfield, double t)
{
- scrollContainers.ForEach(c =>
+ var obj = new TestDrawableControlPoint(playfield.Direction, t);
+ setAnchor(obj, playfield);
+ return obj;
+ }
+
+ private void addControlPoints(IList controlPoints, double sequenceStartTime)
+ {
+ controlPoints.ForEach(point => point.StartTime += sequenceStartTime);
+
+ scrollContainers.ForEach(container =>
{
- c.ControlPoints.Add(new MultiplierControlPoint(time) { DifficultyPoint = { SpeedMultiplier = 3 } });
- c.ControlPoints.Add(new MultiplierControlPoint(time + 2000) { DifficultyPoint = { SpeedMultiplier = 2 } });
- c.ControlPoints.Add(new MultiplierControlPoint(time + 3000) { DifficultyPoint = { SpeedMultiplier = 1 } });
+ container.ControlPoints.AddRange(controlPoints);
});
- playfields.ForEach(p =>
+ foreach (var playfield in playfields)
{
- TestDrawableControlPoint createDrawablePoint(double t)
- {
- var obj = new TestDrawableControlPoint(p.Direction, t);
- setAnchor(obj, p);
- return obj;
- }
-
- p.Add(createDrawablePoint(time));
- p.Add(createDrawablePoint(time + 2000));
- p.Add(createDrawablePoint(time + 3000));
- });
+ foreach (var controlPoint in controlPoints)
+ playfield.Add(createDrawablePoint(playfield, controlPoint.StartTime));
+ }
}
private void setAnchor(DrawableHitObject obj, TestPlayfield playfield)
@@ -236,7 +262,11 @@ namespace osu.Game.Tests.Visual.Gameplay
AutoSizeAxes = Axes.Both;
- AddInternal(new Box { Size = new Vector2(75) });
+ AddInternal(new Box
+ {
+ Size = new Vector2(75),
+ Colour = new Color4(RNG.NextSingle(), RNG.NextSingle(), RNG.NextSingle(), 1)
+ });
}
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
index af21007efe..b9b13d7bd8 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
@@ -1,12 +1,17 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Testing;
+using osu.Framework.Utils;
using osu.Framework.Timing;
+using osu.Game.Graphics;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Play;
@@ -15,63 +20,125 @@ namespace osu.Game.Tests.Visual.Gameplay
[TestFixture]
public class TestSceneSongProgress : OsuTestScene
{
- private readonly SongProgress progress;
- private readonly TestSongProgressGraph graph;
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(SongProgressBar),
+ };
+
+ private SongProgress progress;
+ private TestSongProgressGraph graph;
+ private readonly Container progressContainer;
private readonly StopwatchClock clock;
+ private readonly FramedClock framedClock;
[Cached]
private readonly GameplayClock gameplayClock;
- private readonly FramedClock framedClock;
-
public TestSceneSongProgress()
{
- clock = new StopwatchClock(true);
-
+ clock = new StopwatchClock();
gameplayClock = new GameplayClock(framedClock = new FramedClock(clock));
- Add(progress = new SongProgress
+ Add(progressContainer = new Container
{
RelativeSizeAxes = Axes.X,
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
+ Anchor = Anchor.BottomCentre,
+ Origin = Anchor.BottomCentre,
+ Height = 100,
+ Y = -100,
+ Child = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.Gray(1),
+ }
});
-
- Add(graph = new TestSongProgressGraph
- {
- RelativeSizeAxes = Axes.X,
- Height = 200,
- Anchor = Anchor.TopLeft,
- Origin = Anchor.TopLeft,
- });
-
- AddWaitStep("wait some", 5);
- AddAssert("ensure not created", () => graph.CreationCount == 0);
-
- AddStep("display values", displayNewValues);
- AddWaitStep("wait some", 5);
- AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
-
- AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking);
- AddWaitStep("wait some", 5);
- AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
-
- AddStep("Toggle Bar", () => progress.AllowSeeking = !progress.AllowSeeking);
- AddWaitStep("wait some", 5);
- AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
- AddRepeatStep("New Values", displayNewValues, 5);
-
- AddWaitStep("wait some", 5);
- AddAssert("ensure debounced", () => graph.CreationCount == 2);
}
- private void displayNewValues()
+ [SetUpSteps]
+ public void SetupSteps()
{
- List objects = new List();
+ AddStep("add new song progress", () =>
+ {
+ if (progress != null)
+ {
+ progress.Expire();
+ progress = null;
+ }
+
+ progressContainer.Add(progress = new SongProgress
+ {
+ RelativeSizeAxes = Axes.X,
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ });
+ });
+
+ AddStep("add new big graph", () =>
+ {
+ if (graph != null)
+ {
+ graph.Expire();
+ graph = null;
+ }
+
+ Add(graph = new TestSongProgressGraph
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 200,
+ Anchor = Anchor.TopLeft,
+ Origin = Anchor.TopLeft,
+ });
+ });
+
+ AddStep("reset clock", clock.Reset);
+ }
+
+ [Test]
+ public void TestGraphRecreation()
+ {
+ AddAssert("ensure not created", () => graph.CreationCount == 0);
+ AddStep("display values", displayRandomValues);
+ AddUntilStep("wait for creation count", () => graph.CreationCount == 1);
+ AddRepeatStep("new values", displayRandomValues, 5);
+ AddWaitStep("wait some", 5);
+ AddAssert("ensure recreation debounced", () => graph.CreationCount == 2);
+ }
+
+ [Test]
+ public void TestDisplay()
+ {
+ AddStep("display max values", displayMaxValues);
+ AddUntilStep("wait for graph", () => graph.CreationCount == 1);
+ AddStep("start", clock.Start);
+ AddStep("allow seeking", () => progress.AllowSeeking.Value = true);
+ AddStep("hide graph", () => progress.ShowGraph.Value = false);
+ AddStep("disallow seeking", () => progress.AllowSeeking.Value = false);
+ AddStep("allow seeking", () => progress.AllowSeeking.Value = true);
+ AddStep("show graph", () => progress.ShowGraph.Value = true);
+ AddStep("stop", clock.Stop);
+ }
+
+ private void displayRandomValues()
+ {
+ var objects = new List();
for (double i = 0; i < 5000; i += RNG.NextDouble() * 10 + i / 1000)
objects.Add(new HitObject { StartTime = i });
+ replaceObjects(objects);
+ }
+
+ private void displayMaxValues()
+ {
+ var objects = new List();
+ for (double i = 0; i < 5000; i++)
+ objects.Add(new HitObject { StartTime = i });
+
+ replaceObjects(objects);
+ }
+
+ private void replaceObjects(List objects)
+ {
progress.Objects = objects;
graph.Objects = objects;
diff --git a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs
index d03d341ee4..5870ef9813 100644
--- a/osu.Game.Tests/Visual/Menus/IntroTestScene.cs
+++ b/osu.Game.Tests/Visual/Menus/IntroTestScene.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Menus
protected IntroTestScene()
{
- Drawable introStack = null;
+ OsuScreenStack introStack = null;
Children = new Drawable[]
{
@@ -57,10 +57,12 @@ namespace osu.Game.Tests.Visual.Menus
introStack?.Expire();
- Add(introStack = new OsuScreenStack(CreateScreen())
+ Add(introStack = new OsuScreenStack
{
RelativeSizeAxes = Axes.Both,
});
+
+ introStack.Push(CreateScreen());
});
}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs b/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs
new file mode 100644
index 0000000000..d7f23f5cc0
--- /dev/null
+++ b/osu.Game.Tests/Visual/Menus/TestSceneSongTicker.cs
@@ -0,0 +1,36 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
+using osu.Game.Screens.Menu;
+
+namespace osu.Game.Tests.Visual.Menus
+{
+ public class TestSceneSongTicker : OsuTestScene
+ {
+ [Cached]
+ private MusicController musicController = new MusicController();
+
+ public TestSceneSongTicker()
+ {
+ AddRange(new Drawable[]
+ {
+ musicController,
+ new SongTicker
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ new NowPlayingOverlay
+ {
+ Origin = Anchor.TopRight,
+ Anchor = Anchor.TopRight,
+ State = { Value = Visibility.Visible }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
index eb4dc909df..b5d946d049 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs
@@ -4,11 +4,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Online.Multiplayer;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Catch;
+using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Multi;
using osu.Game.Screens.Multi.Lounge.Components;
using osu.Game.Users;
@@ -27,11 +32,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
[Cached(Type = typeof(IRoomManager))]
private TestRoomManager roomManager = new TestRoomManager();
+ private RoomsContainer container;
+
[BackgroundDependencyLoader]
private void load()
{
- RoomsContainer container;
-
Child = container = new RoomsContainer
{
Anchor = Anchor.Centre,
@@ -39,24 +44,21 @@ namespace osu.Game.Tests.Visual.Multiplayer
Width = 0.5f,
JoinRequested = joinRequested
};
+ }
+
+ public override void SetUpSteps()
+ {
+ base.SetUpSteps();
AddStep("clear rooms", () => roomManager.Rooms.Clear());
+ }
- AddStep("add rooms", () =>
- {
- for (int i = 0; i < 3; i++)
- {
- roomManager.Rooms.Add(new Room
- {
- RoomID = { Value = i },
- Name = { Value = $"Room {i}" },
- Host = { Value = new User { Username = "Host" } },
- EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }
- });
- }
- });
+ [Test]
+ public void TestBasicListChanges()
+ {
+ addRooms(3);
- AddAssert("has 2 rooms", () => container.Rooms.Count == 3);
+ AddAssert("has 3 rooms", () => container.Rooms.Count == 3);
AddStep("remove first room", () => roomManager.Rooms.Remove(roomManager.Rooms.FirstOrDefault()));
AddAssert("has 2 rooms", () => container.Rooms.Count == 2);
AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0));
@@ -68,6 +70,73 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddAssert("first room joined", () => roomManager.Rooms.First().Status.Value is JoinedRoomStatus);
}
+ [Test]
+ public void TestStringFiltering()
+ {
+ addRooms(4);
+
+ AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4);
+
+ AddStep("filter one room", () => container.Filter(new FilterCriteria { SearchString = "1" }));
+
+ AddUntilStep("1 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 1);
+
+ AddStep("remove filter", () => container.Filter(null));
+
+ AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4);
+ }
+
+ [Test]
+ public void TestRulesetFiltering()
+ {
+ addRooms(2, new OsuRuleset().RulesetInfo);
+ addRooms(3, new CatchRuleset().RulesetInfo);
+
+ AddUntilStep("5 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 5);
+
+ AddStep("filter osu! rooms", () => container.Filter(new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo }));
+
+ AddUntilStep("2 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 2);
+
+ AddStep("filter catch rooms", () => container.Filter(new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo }));
+
+ AddUntilStep("3 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 3);
+ }
+
+ private void addRooms(int count, RulesetInfo ruleset = null)
+ {
+ AddStep("add rooms", () =>
+ {
+ for (int i = 0; i < count; i++)
+ {
+ var room = new Room
+ {
+ RoomID = { Value = i },
+ Name = { Value = $"Room {i}" },
+ Host = { Value = new User { Username = "Host" } },
+ EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }
+ };
+
+ if (ruleset != null)
+ {
+ room.Playlist.Add(new PlaylistItem
+ {
+ Ruleset = { Value = ruleset },
+ Beatmap =
+ {
+ Value = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata()
+ }
+ }
+ });
+ }
+
+ roomManager.Rooms.Add(room);
+ }
+ });
+ }
+
private void joinRequested(Room room) => room.Status.Value = new JoinedRoomStatus();
private class TestRoomManager : IRoomManager
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
index 68ad0b42b4..f014b08325 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
@@ -7,7 +7,6 @@ using osu.Game.Beatmaps;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Match.Components;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
using osu.Game.Audio;
using osu.Framework.Allocation;
@@ -32,22 +31,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
Origin = Anchor.Centre,
});
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1763072 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2101557 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1973466 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 2109801 } });
- Room.Playlist.Add(new PlaylistItem { Beatmap = new BeatmapInfo { OnlineBeatmapID = 1922035 } });
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- AddStep("Select random beatmap", () =>
- {
- Room.CurrentItem.Value = Room.Playlist[RNG.Next(Room.Playlist.Count)];
- previewTrackManager.StopAnyPlaying(this);
- });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1763072 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2101557 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1973466 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 2109801 } } });
+ Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = new BeatmapInfo { OnlineBeatmapID = 1922035 } } });
}
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs
index e42042f2ea..7d7e7f85db 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs
@@ -23,16 +23,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
Room.Playlist.Add(new PlaylistItem
{
- Beatmap = new BeatmapInfo
+ Beatmap =
{
- Metadata = new BeatmapMetadata
+ Value = new BeatmapInfo
{
- Title = "Title",
- Artist = "Artist",
- AuthorString = "Author",
- },
- Version = "Version",
- Ruleset = new OsuRuleset().RulesetInfo
+ Metadata = new BeatmapMetadata
+ {
+ Title = "Title",
+ Artist = "Artist",
+ AuthorString = "Author",
+ },
+ Version = "Version",
+ Ruleset = new OsuRuleset().RulesetInfo
+ }
},
RequiredMods =
{
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs
index a6c036a876..6ee9ceb2dd 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchInfo.cs
@@ -37,16 +37,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem
{
- Beatmap = new BeatmapInfo
+ Beatmap =
{
- StarDifficulty = 2.4,
- Ruleset = rulesets.GetRuleset(0),
- Metadata = new BeatmapMetadata
+ Value = new BeatmapInfo
{
- Title = @"My Song",
- Artist = @"VisualTests",
- AuthorString = @"osu!lazer",
- },
+ StarDifficulty = 2.4,
+ Ruleset = rulesets.GetRuleset(0),
+ Metadata = new BeatmapMetadata
+ {
+ Title = @"My Song",
+ Artist = @"VisualTests",
+ AuthorString = @"osu!lazer",
+ },
+ }
}
});
});
@@ -60,16 +63,19 @@ namespace osu.Game.Tests.Visual.Multiplayer
Room.Playlist.Clear();
Room.Playlist.Add(new PlaylistItem
{
- Beatmap = new BeatmapInfo
+ Beatmap =
{
- StarDifficulty = 4.2,
- Ruleset = rulesets.GetRuleset(3),
- Metadata = new BeatmapMetadata
+ Value = new BeatmapInfo
{
- Title = @"Your Song",
- Artist = @"Tester",
- AuthorString = @"Someone",
- },
+ StarDifficulty = 4.2,
+ Ruleset = rulesets.GetRuleset(3),
+ Metadata = new BeatmapMetadata
+ {
+ Title = @"Your Song",
+ Artist = @"Tester",
+ AuthorString = @"Someone",
+ },
+ }
}
});
});
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs
index 1ac914e27d..a6f47961e9 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchParticipants.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
Add(new Participants { RelativeSizeAxes = Axes.Both });
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
- AddStep(@"set users", () => Room.Participants.Value = new[]
+ AddStep(@"set users", () => Room.Participants.AddRange(new[]
{
new User
{
@@ -42,10 +42,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/5287410/5cfeaa9dd41cbce038ecdc9d781396ed4b0108089170bf7f50492ef8eadeb368.jpeg",
IsSupporter = true,
},
- });
+ }));
AddStep(@"set max", () => Room.MaxParticipants.Value = 10);
- AddStep(@"clear users", () => Room.Participants.Value = System.Array.Empty());
+ AddStep(@"clear users", () => Room.Participants.Clear());
AddStep(@"set max to null", () => Room.MaxParticipants.Value = null);
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
index 8d842fc865..047e9d860d 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
AddStep("set name", () => Room.Name.Value = "Room name");
AddAssert("button disabled", () => !settings.ApplyButton.Enabled.Value);
- AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = CreateBeatmap(Ruleset.Value).BeatmapInfo }));
+ AddStep("set beatmap", () => Room.Playlist.Add(new PlaylistItem { Beatmap = { Value = CreateBeatmap(Ruleset.Value).BeatmapInfo } }));
AddAssert("button enabled", () => settings.ApplyButton.Enabled.Value);
AddStep("clear name", () => Room.Name.Value = "");
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs
index 3f89f636b1..76ab402b72 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiHeader.cs
@@ -16,7 +16,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
int index = 0;
- OsuScreenStack screenStack = new OsuScreenStack(new TestMultiplayerSubScreen(index)) { RelativeSizeAxes = Axes.Both };
+ OsuScreenStack screenStack = new OsuScreenStack { RelativeSizeAxes = Axes.Both };
+
+ screenStack.Push(new TestMultiplayerSubScreen(index));
Children = new Drawable[]
{
diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
new file mode 100644
index 0000000000..8d2e4a614d
--- /dev/null
+++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
@@ -0,0 +1,133 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Configuration;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Platform;
+using osu.Framework.Screens;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Configuration;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.API;
+using osu.Game.Overlays;
+using osu.Game.Rulesets;
+using osu.Game.Screens;
+using osu.Game.Screens.Menu;
+using osuTK.Graphics;
+using IntroSequence = osu.Game.Configuration.IntroSequence;
+
+namespace osu.Game.Tests.Visual.Navigation
+{
+ ///
+ /// A scene which tests full game flow.
+ ///
+ public abstract class OsuGameTestScene : ManualInputManagerTestScene
+ {
+ private GameHost host;
+
+ protected TestOsuGame Game;
+
+ [BackgroundDependencyLoader]
+ private void load(GameHost host)
+ {
+ this.host = host;
+
+ Child = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ };
+ }
+
+ [SetUpSteps]
+ public void SetUpSteps()
+ {
+ AddStep("Create new game instance", () =>
+ {
+ if (Game != null)
+ {
+ Remove(Game);
+ Game.Dispose();
+ }
+
+ RecycleLocalStorage();
+
+ // see MouseSettings
+ var frameworkConfig = host.Dependencies.Get();
+ frameworkConfig.GetBindable(FrameworkSetting.CursorSensitivity).Disabled = false;
+
+ Game = new TestOsuGame(LocalStorage, API);
+ Game.SetHost(host);
+
+ // todo: this can be removed once we can run audio tracks without a device present
+ // see https://github.com/ppy/osu/issues/1302
+ Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
+
+ Add(Game);
+ });
+
+ AddUntilStep("Wait for load", () => Game.IsLoaded);
+ AddUntilStep("Wait for intro", () => Game.ScreenStack.CurrentScreen is IntroScreen);
+
+ ConfirmAtMainMenu();
+ }
+
+ protected void PushAndConfirm(Func newScreen)
+ {
+ Screen screen = null;
+ AddStep("Push new screen", () => Game.ScreenStack.Push(screen = newScreen()));
+ AddUntilStep("Wait for new screen", () => Game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
+ }
+
+ protected void ConfirmAtMainMenu() => AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded);
+
+ public class TestOsuGame : OsuGame
+ {
+ public new ScreenStack ScreenStack => base.ScreenStack;
+
+ public new BackButton BackButton => base.BackButton;
+
+ public new BeatmapManager BeatmapManager => base.BeatmapManager;
+
+ public new SettingsPanel Settings => base.Settings;
+
+ public new OsuConfigManager LocalConfig => base.LocalConfig;
+
+ public new Bindable Beatmap => base.Beatmap;
+
+ public new Bindable Ruleset => base.Ruleset;
+
+ protected override Loader CreateLoader() => new TestLoader();
+
+ public new void PerformFromScreen(Action action, IEnumerable validScreens = null) => base.PerformFromScreen(action, validScreens);
+
+ public TestOsuGame(Storage storage, IAPIProvider api)
+ {
+ Storage = storage;
+ API = api;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ API.Login("Rhythm Champion", "osu!");
+ }
+ }
+
+ public class TestLoader : Loader
+ {
+ protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler();
+
+ private class TestShaderPrecompiler : ShaderPrecompiler
+ {
+ protected override bool AllLoaded => true;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
new file mode 100644
index 0000000000..75c6a2b733
--- /dev/null
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs
@@ -0,0 +1,72 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Screens.Menu;
+using osu.Game.Screens.Play;
+using osu.Game.Screens.Select;
+
+namespace osu.Game.Tests.Visual.Navigation
+{
+ public class TestScenePerformFromScreen : OsuGameTestScene
+ {
+ [Test]
+ public void TestPerformAtMenu()
+ {
+ AddAssert("could perform immediately", () =>
+ {
+ bool actionPerformed = false;
+ Game.PerformFromScreen(_ => actionPerformed = true);
+ return actionPerformed;
+ });
+ }
+
+ [Test]
+ public void TestPerformAtSongSelect()
+ {
+ PushAndConfirm(() => new PlaySongSelect());
+
+ AddAssert("could perform immediately", () =>
+ {
+ bool actionPerformed = false;
+ Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) });
+ return actionPerformed;
+ });
+ }
+
+ [Test]
+ public void TestPerformAtMenuFromSongSelect()
+ {
+ PushAndConfirm(() => new PlaySongSelect());
+
+ bool actionPerformed = false;
+ AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
+ AddUntilStep("returned to menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
+ AddAssert("did perform", () => actionPerformed);
+ }
+
+ [Test]
+ public void TestPerformAtSongSelectFromPlayerLoader()
+ {
+ PushAndConfirm(() => new PlaySongSelect());
+ PushAndConfirm(() => new PlayerLoader(() => new Player()));
+
+ bool actionPerformed = false;
+ AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) }));
+ AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
+ AddAssert("did perform", () => actionPerformed);
+ }
+
+ [Test]
+ public void TestPerformAtMenuFromPlayerLoader()
+ {
+ PushAndConfirm(() => new PlaySongSelect());
+ PushAndConfirm(() => new PlayerLoader(() => new Player()));
+
+ bool actionPerformed = false;
+ AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
+ AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is MainMenu);
+ AddAssert("did perform", () => actionPerformed);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
new file mode 100644
index 0000000000..909409835c
--- /dev/null
+++ b/osu.Game.Tests/Visual/Navigation/TestScenePresentBeatmap.cs
@@ -0,0 +1,110 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Screens;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mania;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Screens.Menu;
+
+namespace osu.Game.Tests.Visual.Navigation
+{
+ public class TestScenePresentBeatmap : OsuGameTestScene
+ {
+ [Test]
+ public void TestFromMainMenu()
+ {
+ var firstImport = importBeatmap(1);
+ presentAndConfirm(firstImport);
+
+ AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
+ AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
+
+ var secondimport = importBeatmap(2);
+ presentAndConfirm(secondimport);
+ }
+
+ [Test]
+ public void TestFromMainMenuDifferentRuleset()
+ {
+ var firstImport = importBeatmap(1);
+ presentAndConfirm(firstImport);
+
+ AddStep("return to menu", () => Game.ScreenStack.CurrentScreen.Exit());
+ AddUntilStep("wait for menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
+
+ var secondimport = importBeatmap(2, new ManiaRuleset().RulesetInfo);
+ presentAndConfirm(secondimport);
+ }
+
+ [Test]
+ public void TestFromSongSelect()
+ {
+ var firstImport = importBeatmap(1);
+ presentAndConfirm(firstImport);
+
+ var secondimport = importBeatmap(2);
+ presentAndConfirm(secondimport);
+ }
+
+ [Test]
+ public void TestFromSongSelectDifferentRuleset()
+ {
+ var firstImport = importBeatmap(1);
+ presentAndConfirm(firstImport);
+
+ var secondimport = importBeatmap(2, new ManiaRuleset().RulesetInfo);
+ presentAndConfirm(secondimport);
+ }
+
+ private Func importBeatmap(int i, RulesetInfo ruleset = null)
+ {
+ BeatmapSetInfo imported = null;
+ AddStep($"import beatmap {i}", () =>
+ {
+ var difficulty = new BeatmapDifficulty();
+ var metadata = new BeatmapMetadata
+ {
+ Artist = "SomeArtist",
+ AuthorString = "SomeAuthor",
+ Title = $"import {i}"
+ };
+
+ imported = Game.BeatmapManager.Import(new BeatmapSetInfo
+ {
+ Hash = Guid.NewGuid().ToString(),
+ OnlineBeatmapSetID = i,
+ Metadata = metadata,
+ Beatmaps = new List
+ {
+ new BeatmapInfo
+ {
+ OnlineBeatmapID = i * 1024,
+ Metadata = metadata,
+ BaseDifficulty = difficulty,
+ Ruleset = ruleset ?? new OsuRuleset().RulesetInfo
+ },
+ }
+ }).Result;
+ });
+
+ AddAssert($"import {i} succeeded", () => imported != null);
+
+ return () => imported;
+ }
+
+ private void presentAndConfirm(Func getImport)
+ {
+ AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
+
+ AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
+ AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.ID == getImport().ID);
+ AddAssert("correct ruleset selected", () => Game.Ruleset.Value.ID == getImport().Beatmaps.First().Ruleset.ID);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
similarity index 50%
rename from osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs
rename to osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
index 471f67b7b6..8258cc9465 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneScreenNavigation.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
@@ -1,90 +1,36 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio.Track;
-using osu.Framework.Bindables;
-using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Platform;
-using osu.Framework.Screens;
-using osu.Framework.Testing;
using osu.Game.Beatmaps;
-using osu.Game.Configuration;
-using osu.Game.Graphics.UserInterface;
-using osu.Game.Online.API;
using osu.Game.Overlays;
using osu.Game.Overlays.Mods;
-using osu.Game.Screens;
-using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select;
using osu.Game.Tests.Beatmaps.IO;
using osuTK;
-using osuTK.Graphics;
using osuTK.Input;
-using IntroSequence = osu.Game.Configuration.IntroSequence;
-namespace osu.Game.Tests.Visual.Menus
+namespace osu.Game.Tests.Visual.Navigation
{
- public class TestSceneScreenNavigation : ManualInputManagerTestScene
+ public class TestSceneScreenNavigation : OsuGameTestScene
{
private const float click_padding = 25;
- private GameHost host;
- private TestOsuGame game;
+ private Vector2 backButtonPosition => Game.ToScreenSpace(new Vector2(click_padding, Game.LayoutRectangle.Bottom - click_padding));
- private Vector2 backButtonPosition => game.ToScreenSpace(new Vector2(click_padding, game.LayoutRectangle.Bottom - click_padding));
-
- private Vector2 optionsButtonPosition => game.ToScreenSpace(new Vector2(click_padding, click_padding));
-
- [BackgroundDependencyLoader]
- private void load(GameHost host)
- {
- this.host = host;
-
- Child = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
- };
- }
-
- [SetUpSteps]
- public void SetUpSteps()
- {
- AddStep("Create new game instance", () =>
- {
- if (game != null)
- {
- Remove(game);
- game.Dispose();
- }
-
- game = new TestOsuGame(LocalStorage, API);
- game.SetHost(host);
-
- // todo: this can be removed once we can run audio trakcs without a device present
- // see https://github.com/ppy/osu/issues/1302
- game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
-
- Add(game);
- });
- AddUntilStep("Wait for load", () => game.IsLoaded);
- AddUntilStep("Wait for intro", () => game.ScreenStack.CurrentScreen is IntroScreen);
- confirmAtMainMenu();
- }
+ private Vector2 optionsButtonPosition => Game.ToScreenSpace(new Vector2(click_padding, click_padding));
[Test]
public void TestExitSongSelectWithEscape()
{
TestSongSelect songSelect = null;
- pushAndConfirm(() => songSelect = new TestSongSelect());
+ PushAndConfirm(() => songSelect = new TestSongSelect());
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
pushEscape();
@@ -98,21 +44,21 @@ namespace osu.Game.Tests.Visual.Menus
{
Player player = null;
- WorkingBeatmap beatmap() => game.Beatmap.Value;
+ WorkingBeatmap beatmap() => Game.Beatmap.Value;
Track track() => beatmap().Track;
- pushAndConfirm(() => new TestSongSelect());
+ PushAndConfirm(() => new TestSongSelect());
- AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Wait());
+ AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait());
- AddUntilStep("wait for selected", () => !game.Beatmap.IsDefault);
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
if (withUserPause)
- AddStep("pause", () => game.Dependencies.Get().Stop());
+ AddStep("pause", () => Game.Dependencies.Get().Stop());
AddStep("press enter", () => pressAndRelease(Key.Enter));
- AddUntilStep("wait for player", () => (player = game.ScreenStack.CurrentScreen as Player) != null);
+ AddUntilStep("wait for player", () => (player = Game.ScreenStack.CurrentScreen as Player) != null);
AddUntilStep("wait for fail", () => player.HasFailed);
AddUntilStep("wait for track stop", () => !track().IsRunning);
@@ -129,13 +75,13 @@ namespace osu.Game.Tests.Visual.Menus
{
TestSongSelect songSelect = null;
- pushAndConfirm(() => songSelect = new TestSongSelect());
+ PushAndConfirm(() => songSelect = new TestSongSelect());
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
// BackButton handles hover using its child button, so this checks whether or not any of BackButton's children are hovered.
- AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == game.BackButton));
+ AddUntilStep("Back button is hovered", () => InputManager.HoveredDrawables.Any(d => d.Parent == Game.BackButton));
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
AddUntilStep("Overlay was hidden", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
@@ -145,34 +91,27 @@ namespace osu.Game.Tests.Visual.Menus
[Test]
public void TestExitMultiWithEscape()
{
- pushAndConfirm(() => new Screens.Multi.Multiplayer());
+ PushAndConfirm(() => new Screens.Multi.Multiplayer());
exitViaEscapeAndConfirm();
}
[Test]
public void TestExitMultiWithBackButton()
{
- pushAndConfirm(() => new Screens.Multi.Multiplayer());
+ PushAndConfirm(() => new Screens.Multi.Multiplayer());
exitViaBackButtonAndConfirm();
}
[Test]
public void TestOpenOptionsAndExitWithEscape()
{
- AddUntilStep("Wait for options to load", () => game.Settings.IsLoaded);
+ AddUntilStep("Wait for options to load", () => Game.Settings.IsLoaded);
AddStep("Enter menu", () => pressAndRelease(Key.Enter));
AddStep("Move mouse to options overlay", () => InputManager.MoveMouseTo(optionsButtonPosition));
AddStep("Click options overlay", () => InputManager.Click(MouseButton.Left));
- AddAssert("Options overlay was opened", () => game.Settings.State.Value == Visibility.Visible);
+ AddAssert("Options overlay was opened", () => Game.Settings.State.Value == Visibility.Visible);
AddStep("Hide options overlay using escape", () => pressAndRelease(Key.Escape));
- AddAssert("Options overlay was closed", () => game.Settings.State.Value == Visibility.Hidden);
- }
-
- private void pushAndConfirm(Func newScreen)
- {
- Screen screen = null;
- AddStep("Push new screen", () => game.ScreenStack.Push(screen = newScreen()));
- AddUntilStep("Wait for new screen", () => game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
+ AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
}
private void pushEscape() =>
@@ -181,64 +120,25 @@ namespace osu.Game.Tests.Visual.Menus
private void exitViaEscapeAndConfirm()
{
pushEscape();
- confirmAtMainMenu();
+ ConfirmAtMainMenu();
}
private void exitViaBackButtonAndConfirm()
{
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
AddStep("Click back button", () => InputManager.Click(MouseButton.Left));
- confirmAtMainMenu();
+ ConfirmAtMainMenu();
}
- private void confirmAtMainMenu() => AddUntilStep("Wait for main menu", () => game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded);
-
private void pressAndRelease(Key key)
{
InputManager.PressKey(key);
InputManager.ReleaseKey(key);
}
- private class TestOsuGame : OsuGame
- {
- public new ScreenStack ScreenStack => base.ScreenStack;
-
- public new BackButton BackButton => base.BackButton;
-
- public new SettingsPanel Settings => base.Settings;
-
- public new OsuConfigManager LocalConfig => base.LocalConfig;
-
- public new Bindable Beatmap => base.Beatmap;
-
- protected override Loader CreateLoader() => new TestLoader();
-
- public TestOsuGame(Storage storage, IAPIProvider api)
- {
- Storage = storage;
- API = api;
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- API.Login("Rhythm Champion", "osu!");
- }
- }
-
private class TestSongSelect : PlaySongSelect
{
public ModSelectOverlay ModSelectOverlay => ModSelect;
}
-
- private class TestLoader : Loader
- {
- protected override ShaderPrecompiler CreateShaderPrecompiler() => new TestShaderPrecompiler();
-
- private class TestShaderPrecompiler : ShaderPrecompiler
- {
- protected override bool AllLoaded => true;
- }
- }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
index 1f8df438fb..8b077c8de3 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapRulesetSelector.cs
@@ -5,6 +5,7 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Beatmaps;
+using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Rulesets;
using System;
@@ -21,6 +22,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(BeatmapRulesetTabItem),
};
+ [Cached]
+ private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
private readonly TestRulesetSelector selector;
public TestSceneBeatmapRulesetSelector()
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
index 96c0c59695..dea1e710b5 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
@@ -5,9 +5,11 @@ using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
+using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
@@ -22,6 +24,9 @@ namespace osu.Game.Tests.Visual.Online
private RatingsExposingDetails details;
+ [Cached]
+ private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
[SetUp]
public void Setup() => Schedule(() =>
{
@@ -55,8 +60,12 @@ namespace osu.Game.Tests.Visual.Online
{
Fails = Enumerable.Range(1, 100).Select(_ => RNG.Next(10)).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(_ => RNG.Next(10)).ToArray(),
- }
+ },
}
+ },
+ OnlineInfo = new BeatmapSetOnlineInfo
+ {
+ Status = BeatmapSetOnlineStatus.Ranked
}
};
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
index 80fad44593..03003daf81 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
@@ -5,11 +5,13 @@ 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.Shapes;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
+using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
using osuTK;
@@ -26,6 +28,9 @@ namespace osu.Game.Tests.Visual.Online
private GraphExposingSuccessRate successRate;
+ [Cached]
+ private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
[SetUp]
public void Setup() => Schedule(() =>
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
index 658f678b10..7a8570c09b 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Tests.Visual.Online
[TestFixture]
public class TestSceneChangelogOverlay : OsuTestScene
{
- private ChangelogOverlay changelog;
+ private TestChangelogOverlay changelog;
public override IReadOnlyList RequiredTypes => new[]
{
@@ -29,23 +29,40 @@ namespace osu.Game.Tests.Visual.Online
protected override bool UseOnlineAPI => true;
- protected override void LoadComplete()
+ [SetUp]
+ public void SetUp() => Schedule(() =>
{
- base.LoadComplete();
+ Child = changelog = new TestChangelogOverlay();
+ });
- Add(changelog = new ChangelogOverlay());
- AddStep(@"Show", changelog.Show);
- AddStep(@"Hide", changelog.Hide);
+ [Test]
+ public void ShowWithNoFetch()
+ {
+ AddStep(@"Show", () => changelog.Show());
+ AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0);
+ AddAssert(@"listing displayed", () => changelog.Current.Value == null);
+ AddAssert(@"no stream selected", () => changelog.Header.Streams.Current.Value == null);
+ }
- AddWaitStep("wait for hide", 3);
+ [Test]
+ public void ShowWithListing()
+ {
+ AddStep(@"Show with listing", () => changelog.ShowListing());
+ AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0);
+ AddAssert(@"listing displayed", () => changelog.Current.Value == null);
+ AddAssert(@"no stream selected", () => changelog.Header.Streams.Current.Value == null);
+ }
+ [Test]
+ public void ShowWithBuild()
+ {
AddStep(@"Show with Lazer 2018.712.0", () =>
{
changelog.ShowBuild(new APIChangelogBuild
{
Version = "2018.712.0",
DisplayVersion = "2018.712.0",
- UpdateStream = new APIUpdateStream { Name = OsuGameBase.CLIENT_STREAM_NAME },
+ UpdateStream = new APIUpdateStream { Id = 7, Name = OsuGameBase.CLIENT_STREAM_NAME },
ChangelogEntries = new List
{
new APIChangelogEntry
@@ -56,19 +73,16 @@ namespace osu.Game.Tests.Visual.Online
}
}
});
- changelog.Show();
});
- AddWaitStep("wait for show", 3);
- AddStep(@"Hide", changelog.Hide);
- AddWaitStep("wait for hide", 3);
-
- AddStep(@"Show with listing", () =>
- {
- changelog.ShowListing();
- changelog.Show();
- });
+ AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0);
+ AddAssert(@"correct build displayed", () => changelog.Current.Value.Version == "2018.712.0");
+ AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 7);
+ }
+ [Test]
+ public void TestHTMLUnescaping()
+ {
AddStep(@"Ensure HTML string unescaping", () =>
{
changelog.ShowBuild(new APIChangelogBuild
@@ -97,5 +111,12 @@ namespace osu.Game.Tests.Visual.Online
});
});
}
+
+ private class TestChangelogOverlay : ChangelogOverlay
+ {
+ public new List Streams => base.Streams;
+
+ public new ChangelogHeader Header => base.Header;
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
index 16e47c5df9..1fb3f4ba45 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChannelTabControl.cs
@@ -5,11 +5,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osu.Game.Overlays.Chat.Tabs;
@@ -25,7 +26,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(ChannelTabControl),
};
- private readonly ChannelTabControl channelTabControl;
+ private readonly TestTabControl channelTabControl;
public TestSceneChannelTabControl()
{
@@ -37,7 +38,7 @@ namespace osu.Game.Tests.Visual.Online
Anchor = Anchor.Centre,
Children = new Drawable[]
{
- channelTabControl = new ChannelTabControl
+ channelTabControl = new TestTabControl
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.Centre,
@@ -73,32 +74,40 @@ namespace osu.Game.Tests.Visual.Online
channelTabControl.Current.ValueChanged += channel => currentText.Text = "Currently selected channel: " + channel.NewValue;
AddStep("Add random private channel", addRandomPrivateChannel);
- AddAssert("There is only one channels", () => channelTabControl.Items.Count() == 2);
+ AddAssert("There is only one channels", () => channelTabControl.Items.Count == 2);
AddRepeatStep("Add 3 random private channels", addRandomPrivateChannel, 3);
- AddAssert("There are four channels", () => channelTabControl.Items.Count() == 5);
+ AddAssert("There are four channels", () => channelTabControl.Items.Count == 5);
AddStep("Add random public channel", () => addChannel(RNG.Next().ToString()));
- AddRepeatStep("Select a random channel", () => channelTabControl.Current.Value = channelTabControl.Items.ElementAt(RNG.Next(channelTabControl.Items.Count() - 1)), 20);
+ AddRepeatStep("Select a random channel", () =>
+ {
+ List validChannels = channelTabControl.Items.Where(c => !(c is ChannelSelectorTabItem.ChannelSelectorTabChannel)).ToList();
+ channelTabControl.SelectChannel(validChannels[RNG.Next(0, validChannels.Count)]);
+ }, 20);
- Channel channelBefore = channelTabControl.Items.First();
- AddStep("set first channel", () => channelTabControl.Current.Value = channelBefore);
+ Channel channelBefore = null;
+ AddStep("set first channel", () => channelTabControl.SelectChannel(channelBefore = channelTabControl.Items.First(c => !(c is ChannelSelectorTabItem.ChannelSelectorTabChannel))));
- AddStep("select selector tab", () => channelTabControl.Current.Value = channelTabControl.Items.Last());
+ AddStep("select selector tab", () => channelTabControl.SelectChannel(channelTabControl.Items.Single(c => c is ChannelSelectorTabItem.ChannelSelectorTabChannel)));
AddAssert("selector tab is active", () => channelTabControl.ChannelSelectorActive.Value);
AddAssert("check channel unchanged", () => channelBefore == channelTabControl.Current.Value);
- AddStep("set second channel", () => channelTabControl.Current.Value = channelTabControl.Items.Skip(1).First());
+ AddStep("set second channel", () => channelTabControl.SelectChannel(channelTabControl.Items.GetNext(channelBefore)));
AddAssert("selector tab is inactive", () => !channelTabControl.ChannelSelectorActive.Value);
AddUntilStep("remove all channels", () =>
{
- var first = channelTabControl.Items.First();
- if (first is ChannelSelectorTabItem.ChannelSelectorTabChannel)
- return true;
+ foreach (var item in channelTabControl.Items.ToList())
+ {
+ if (item is ChannelSelectorTabItem.ChannelSelectorTabChannel)
+ continue;
- channelTabControl.RemoveChannel(first);
- return false;
+ channelTabControl.RemoveChannel(item);
+ return false;
+ }
+
+ return true;
});
AddAssert("selector tab is active", () => channelTabControl.ChannelSelectorActive.Value);
@@ -117,5 +126,10 @@ namespace osu.Game.Tests.Visual.Online
Type = ChannelType.Public,
Name = name
});
+
+ private class TestTabControl : ChannelTabControl
+ {
+ public void SelectChannel(Channel channel) => base.SelectTab(TabMap[channel]);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
index 9196513a55..19bdaff6ff 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs
@@ -3,12 +3,15 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Testing;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Chat;
using osu.Game.Overlays;
using osu.Game.Overlays.Chat;
@@ -35,8 +38,21 @@ namespace osu.Game.Tests.Visual.Online
private TestChatOverlay chatOverlay;
private ChannelManager channelManager;
- private readonly Channel channel1 = new Channel(new User()) { Name = "test really long username" };
- private readonly Channel channel2 = new Channel(new User()) { Name = "test2" };
+ private readonly List channels;
+
+ private Channel channel1 => channels[0];
+ private Channel channel2 => channels[1];
+
+ public TestSceneChatOverlay()
+ {
+ channels = Enumerable.Range(1, 10)
+ .Select(index => new Channel(new User())
+ {
+ Name = $"Channel no. {index}",
+ Topic = index == 3 ? null : $"We talk about the number {index} here"
+ })
+ .ToList();
+ }
[SetUp]
public void Setup()
@@ -45,7 +61,7 @@ namespace osu.Game.Tests.Visual.Online
{
ChannelManagerContainer container;
- Child = container = new ChannelManagerContainer(new List { channel1, channel2 })
+ Child = container = new ChannelManagerContainer(channels)
{
RelativeSizeAxes = Axes.Both,
};
@@ -96,6 +112,47 @@ namespace osu.Game.Tests.Visual.Online
AddAssert("Selector is visible", () => chatOverlay.SelectionOverlayState == Visibility.Visible);
}
+ [Test]
+ public void TestSearchInSelector()
+ {
+ AddStep("search for 'no. 2'", () => chatOverlay.ChildrenOfType().First().Text = "no. 2");
+ AddUntilStep("only channel 2 visible", () =>
+ {
+ var listItems = chatOverlay.ChildrenOfType().Where(c => c.IsPresent);
+ return listItems.Count() == 1 && listItems.Single().Channel == channel2;
+ });
+ }
+
+ [Test]
+ public void TestChannelShortcutKeys()
+ {
+ AddStep("join 10 channels", () => channels.ForEach(channel => channelManager.JoinChannel(channel)));
+ AddStep("close channel selector", () =>
+ {
+ InputManager.PressKey(Key.Escape);
+ InputManager.ReleaseKey(Key.Escape);
+ });
+ AddUntilStep("wait for close", () => chatOverlay.SelectionOverlayState == Visibility.Hidden);
+
+ for (int zeroBasedIndex = 0; zeroBasedIndex < 10; ++zeroBasedIndex)
+ {
+ var oneBasedIndex = zeroBasedIndex + 1;
+ var targetNumberKey = oneBasedIndex % 10;
+ var targetChannel = channels[zeroBasedIndex];
+ AddStep($"press Alt+{targetNumberKey}", () => pressChannelHotkey(targetNumberKey));
+ AddAssert($"channel #{oneBasedIndex} is selected", () => channelManager.CurrentChannel.Value == targetChannel);
+ }
+ }
+
+ private void pressChannelHotkey(int number)
+ {
+ var channelKey = Key.Number0 + number;
+ InputManager.PressKey(Key.AltLeft);
+ InputManager.PressKey(channelKey);
+ InputManager.ReleaseKey(Key.AltLeft);
+ InputManager.ReleaseKey(channelKey);
+ }
+
private void clickDrawable(Drawable d)
{
InputManager.MoveMouseTo(d);
diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs
index 86bd0ddd11..2a43ba3f99 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs
@@ -8,6 +8,10 @@ using osu.Game.Online.API.Requests;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Game.Overlays.Comments;
+using osu.Game.Overlays;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Game.Users;
namespace osu.Game.Tests.Visual.Online
{
@@ -22,38 +26,42 @@ namespace osu.Game.Tests.Visual.Online
typeof(HeaderButton),
typeof(SortTabControl),
typeof(ShowChildrenButton),
- typeof(DeletedChildrenPlaceholder),
- typeof(VotePill)
+ typeof(DeletedCommentsCounter),
+ typeof(VotePill),
+ typeof(CommentsPage),
};
protected override bool UseOnlineAPI => true;
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
+
public TestSceneCommentsContainer()
{
- BasicScrollContainer scrollFlow;
+ BasicScrollContainer scroll;
+ TestCommentsContainer comments;
- Add(scrollFlow = new BasicScrollContainer
+ Add(scroll = new BasicScrollContainer
{
RelativeSizeAxes = Axes.Both,
+ Child = comments = new TestCommentsContainer()
});
- AddStep("Big Black comments", () =>
+ AddStep("Big Black comments", () => comments.ShowComments(CommentableType.Beatmapset, 41823));
+ AddStep("Airman comments", () => comments.ShowComments(CommentableType.Beatmapset, 24313));
+ AddStep("Lazer build comments", () => comments.ShowComments(CommentableType.Build, 4772));
+ AddStep("News comments", () => comments.ShowComments(CommentableType.NewsPost, 715));
+ AddStep("Trigger user change", comments.User.TriggerChange);
+ AddStep("Idle state", () =>
{
- scrollFlow.Clear();
- scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 41823));
+ scroll.Clear();
+ scroll.Add(comments = new TestCommentsContainer());
});
+ }
- AddStep("Airman comments", () =>
- {
- scrollFlow.Clear();
- scrollFlow.Add(new CommentsContainer(CommentableType.Beatmapset, 24313));
- });
-
- AddStep("lazer build comments", () =>
- {
- scrollFlow.Clear();
- scrollFlow.Add(new CommentsContainer(CommentableType.Build, 4772));
- });
+ private class TestCommentsContainer : CommentsContainer
+ {
+ public new Bindable User => base.User;
}
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs
index bc3e0eff1a..a60f220e4b 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsHeader.cs
@@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Game.Overlays;
using osu.Game.Overlays.Comments;
namespace osu.Game.Tests.Visual.Online
@@ -19,6 +21,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(SortTabControl),
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
private readonly Bindable sort = new Bindable();
private readonly BindableBool showDeleted = new BindableBool();
diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
new file mode 100644
index 0000000000..1217ce6b42
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
@@ -0,0 +1,162 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Overlays.Comments;
+using osu.Game.Overlays;
+using osu.Framework.Allocation;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Users;
+using osu.Game.Graphics.UserInterface;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneCommentsPage : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(DrawableComment),
+ typeof(CommentsPage),
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
+
+ private readonly BindableBool showDeleted = new BindableBool();
+ private readonly Container content;
+
+ public TestSceneCommentsPage()
+ {
+ Add(new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 10),
+ Children = new Drawable[]
+ {
+ new Container
+ {
+ AutoSizeAxes = Axes.Y,
+ Width = 200,
+ Child = new OsuCheckbox
+ {
+ Current = showDeleted,
+ LabelText = @"Show Deleted"
+ }
+ },
+ content = new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ }
+ }
+ });
+
+ AddStep("load comments", () => createPage(comment_bundle));
+ AddStep("load empty comments", () => createPage(empty_comment_bundle));
+ }
+
+ private void createPage(CommentBundle commentBundle)
+ {
+ content.Clear();
+ content.Add(new CommentsPage(commentBundle)
+ {
+ ShowDeleted = { BindTarget = showDeleted }
+ });
+ }
+
+ private static readonly CommentBundle empty_comment_bundle = new CommentBundle
+ {
+ Comments = new List(),
+ Total = 0,
+ };
+
+ private static readonly CommentBundle comment_bundle = new CommentBundle
+ {
+ Comments = new List
+ {
+ new Comment
+ {
+ Id = 1,
+ Message = "Simple test comment",
+ LegacyName = "TestUser1",
+ CreatedAt = DateTimeOffset.Now,
+ VotesCount = 5
+ },
+ new Comment
+ {
+ Id = 2,
+ Message = "This comment has been deleted :( but visible for admins",
+ LegacyName = "TestUser2",
+ CreatedAt = DateTimeOffset.Now,
+ DeletedAt = DateTimeOffset.Now,
+ VotesCount = 5
+ },
+ new Comment
+ {
+ Id = 3,
+ Message = "This comment is a top level",
+ LegacyName = "TestUser3",
+ CreatedAt = DateTimeOffset.Now,
+ RepliesCount = 2,
+ },
+ new Comment
+ {
+ Id = 4,
+ ParentId = 3,
+ Message = "And this is a reply",
+ RepliesCount = 1,
+ LegacyName = "TestUser1",
+ CreatedAt = DateTimeOffset.Now,
+ },
+ new Comment
+ {
+ Id = 15,
+ ParentId = 4,
+ Message = "Reply to reply",
+ LegacyName = "TestUser1",
+ CreatedAt = DateTimeOffset.Now,
+ },
+ new Comment
+ {
+ Id = 6,
+ ParentId = 3,
+ LegacyName = "TestUser11515",
+ CreatedAt = DateTimeOffset.Now,
+ DeletedAt = DateTimeOffset.Now,
+ },
+ new Comment
+ {
+ Id = 5,
+ Message = "This comment is voted and edited",
+ LegacyName = "BigBrainUser",
+ CreatedAt = DateTimeOffset.Now,
+ EditedAt = DateTimeOffset.Now,
+ VotesCount = 1000,
+ EditedById = 1,
+ }
+ },
+ IncludedComments = new List(),
+ UserVotes = new List
+ {
+ 5
+ },
+ Users = new List
+ {
+ new User
+ {
+ Id = 1,
+ Username = "Good_Admin"
+ }
+ },
+ TopLevelCount = 4,
+ Total = 7
+ };
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs
index fe8437be17..e60adcee34 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneFullscreenOverlay.cs
@@ -41,6 +41,7 @@ namespace osu.Game.Tests.Visual.Online
private class TestFullscreenOverlay : FullscreenOverlay
{
public TestFullscreenOverlay()
+ : base(OverlayColourScheme.Pink)
{
Children = new Drawable[]
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
index d3b037f499..d098ea8b16 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneHistoricalSection.cs
@@ -4,10 +4,12 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
+using osu.Game.Overlays;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Historical;
using osu.Game.Users;
@@ -24,9 +26,11 @@ namespace osu.Game.Tests.Visual.Online
typeof(HistoricalSection),
typeof(PaginatedMostPlayedBeatmapContainer),
typeof(DrawableMostPlayedBeatmap),
- typeof(DrawableProfileRow)
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
+
public TestSceneHistoricalSection()
{
HistoricalSection section;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs
index cc3b2ac68b..f9a7bc99c3 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneLeaderboardScopeSelector.cs
@@ -7,11 +7,16 @@ using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Bindables;
using osu.Game.Screens.Select.Leaderboards;
+using osu.Framework.Allocation;
+using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneLeaderboardScopeSelector : OsuTestScene
{
+ [Cached]
+ private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
public override IReadOnlyList RequiredTypes => new[]
{
typeof(LeaderboardScopeSelector),
diff --git a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs
index 1f5ba67e03..826624f686 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneProfileRulesetSelector.cs
@@ -11,6 +11,8 @@ using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
using osu.Game.Users;
using osu.Framework.Bindables;
+using osu.Game.Overlays;
+using osu.Framework.Allocation;
namespace osu.Game.Tests.Visual.Online
{
@@ -22,10 +24,13 @@ namespace osu.Game.Tests.Visual.Online
typeof(ProfileRulesetTabItem),
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
public TestSceneProfileRulesetSelector()
{
ProfileRulesetSelector selector;
- Bindable user = new Bindable();
+ var user = new Bindable();
Child = selector = new ProfileRulesetSelector
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs
index c70cc4ae4e..8f7e7498a9 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankGraph.cs
@@ -4,11 +4,13 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays;
using osu.Game.Overlays.Profile.Header.Components;
using osu.Game.Users;
using osuTK;
@@ -24,6 +26,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(LineGraph)
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink);
+
public TestSceneRankGraph()
{
RankGraph graph;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs
new file mode 100644
index 0000000000..79862deb16
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs
@@ -0,0 +1,81 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays.Rankings;
+using osu.Game.Users;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osuTK.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Overlays;
+using osu.Framework.Allocation;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneRankingsCountryFilter : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CountryFilter),
+ typeof(CountryPill)
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
+ public TestSceneRankingsCountryFilter()
+ {
+ var countryBindable = new Bindable();
+
+ AddRange(new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Gray,
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new CountryFilter
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Current = { BindTarget = countryBindable }
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Text = "Some content",
+ Margin = new MarginPadding { Vertical = 20 }
+ }
+ }
+ }
+ });
+
+ var country = new Country
+ {
+ FlagName = "BY",
+ FullName = "Belarus"
+ };
+ var unknownCountry = new Country
+ {
+ FlagName = "CK",
+ FullName = "Cook Islands"
+ };
+
+ AddStep("Set country", () => countryBindable.Value = country);
+ AddStep("Set null country", () => countryBindable.Value = null);
+ AddStep("Set country with no flag", () => countryBindable.Value = unknownCountry);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsDismissableFlag.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsDismissableFlag.cs
deleted file mode 100644
index cd954cd6bd..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsDismissableFlag.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Game.Overlays.Rankings;
-using osu.Game.Users;
-using osuTK;
-
-namespace osu.Game.Tests.Visual.Online
-{
- public class TestSceneRankingsDismissableFlag : OsuTestScene
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(DismissableFlag),
- };
-
- public TestSceneRankingsDismissableFlag()
- {
- DismissableFlag flag;
- SpriteText text;
-
- var countryA = new Country
- {
- FlagName = "BY",
- FullName = "Belarus"
- };
-
- var countryB = new Country
- {
- FlagName = "US",
- FullName = "United States"
- };
-
- AddRange(new Drawable[]
- {
- flag = new DismissableFlag
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(30, 20),
- Country = countryA,
- },
- text = new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Text = "Invoked",
- Font = OsuFont.GetFont(size: 30),
- Alpha = 0,
- }
- });
-
- flag.Action += () => text.FadeIn().Then().FadeOut(1000, Easing.OutQuint);
-
- AddStep("Trigger click", () => flag.Click());
- AddStep("Change to country 2", () => flag.Country = countryB);
- AddStep("Change to country 1", () => flag.Country = countryA);
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs
index e708934bc3..1e711b3cd7 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeader.cs
@@ -3,8 +3,9 @@
using System;
using System.Collections.Generic;
+using osu.Framework.Allocation;
using osu.Framework.Bindables;
-using osu.Framework.Graphics;
+using osu.Game.Overlays;
using osu.Game.Overlays.Rankings;
using osu.Game.Rulesets;
using osu.Game.Users;
@@ -15,44 +16,25 @@ namespace osu.Game.Tests.Visual.Online
{
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(DismissableFlag),
- typeof(HeaderTitle),
- typeof(RankingsRulesetSelector),
- typeof(RankingsScopeSelector),
- typeof(RankingsHeader),
+ typeof(RankingsOverlayHeader),
+ typeof(CountryFilter),
+ typeof(CountryPill)
};
+ [Cached]
+ private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Green);
+
public TestSceneRankingsHeader()
{
var countryBindable = new Bindable();
var ruleset = new Bindable();
var scope = new Bindable();
- Add(new RankingsHeader
+ Add(new RankingsOverlayHeader
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Scope = { BindTarget = scope },
+ Current = { BindTarget = scope },
Country = { BindTarget = countryBindable },
- Ruleset = { BindTarget = ruleset },
- Spotlights = new[]
- {
- new Spotlight
- {
- Id = 1,
- Text = "Spotlight 1"
- },
- new Spotlight
- {
- Id = 2,
- Text = "Spotlight 2"
- },
- new Spotlight
- {
- Id = 3,
- Text = "Spotlight 3"
- }
- }
+ Ruleset = { BindTarget = ruleset }
});
var country = new Country
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeaderTitle.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsHeaderTitle.cs
deleted file mode 100644
index 0edf104da0..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsHeaderTitle.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using osu.Framework.Bindables;
-using osu.Framework.Graphics;
-using osu.Game.Overlays.Rankings;
-using osu.Game.Users;
-
-namespace osu.Game.Tests.Visual.Online
-{
- public class TestSceneRankingsHeaderTitle : OsuTestScene
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(DismissableFlag),
- typeof(HeaderTitle),
- };
-
- public TestSceneRankingsHeaderTitle()
- {
- var countryBindable = new Bindable();
- var scope = new Bindable();
-
- Add(new HeaderTitle
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Country = { BindTarget = countryBindable },
- Scope = { BindTarget = scope },
- });
-
- var countryA = new Country
- {
- FlagName = "BY",
- FullName = "Belarus"
- };
-
- var countryB = new Country
- {
- FlagName = "US",
- FullName = "United States"
- };
-
- AddStep("Set country 1", () => countryBindable.Value = countryA);
- AddStep("Set country 2", () => countryBindable.Value = countryB);
- AddStep("Set null country", () => countryBindable.Value = null);
- AddStep("Set scope to Performance", () => scope.Value = RankingsScope.Performance);
- AddStep("Set scope to Spotlights", () => scope.Value = RankingsScope.Spotlights);
- AddStep("Set scope to Score", () => scope.Value = RankingsScope.Score);
- AddStep("Set scope to Country", () => scope.Value = RankingsScope.Country);
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs
index 568e36df4c..a769ebe4a9 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs
@@ -25,7 +25,8 @@ namespace osu.Game.Tests.Visual.Online
typeof(TableRowBackground),
typeof(UserBasedTable),
typeof(RankingsTable<>),
- typeof(RankingsOverlay)
+ typeof(RankingsOverlay),
+ typeof(RankingsOverlayHeader)
};
[Cached]
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsRulesetSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsRulesetSelector.cs
deleted file mode 100644
index 84515bd3a4..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsRulesetSelector.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using osu.Game.Overlays.Rankings;
-using osu.Framework.Graphics;
-using osu.Game.Rulesets;
-using osu.Framework.Bindables;
-using osu.Game.Rulesets.Osu;
-using osu.Game.Rulesets.Mania;
-using osu.Game.Rulesets.Taiko;
-using osu.Game.Rulesets.Catch;
-
-namespace osu.Game.Tests.Visual.Online
-{
- public class TestSceneRankingsRulesetSelector : OsuTestScene
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(RankingsRulesetSelector),
- };
-
- public TestSceneRankingsRulesetSelector()
- {
- var current = new Bindable();
-
- Add(new RankingsRulesetSelector
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Current = { BindTarget = current }
- });
-
- AddStep("Select osu!", () => current.Value = new OsuRuleset().RulesetInfo);
- AddStep("Select mania", () => current.Value = new ManiaRuleset().RulesetInfo);
- AddStep("Select taiko", () => current.Value = new TaikoRuleset().RulesetInfo);
- AddStep("Select catch", () => current.Value = new CatchRuleset().RulesetInfo);
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsScopeSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsScopeSelector.cs
deleted file mode 100644
index 3693d6b5b4..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsScopeSelector.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using osu.Framework.Graphics;
-using osu.Framework.Bindables;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Allocation;
-using osu.Game.Graphics;
-using osu.Game.Overlays.Rankings;
-
-namespace osu.Game.Tests.Visual.Online
-{
- public class TestSceneRankingsScopeSelector : OsuTestScene
- {
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(RankingsScopeSelector),
- };
-
- private readonly Box background;
-
- public TestSceneRankingsScopeSelector()
- {
- var scope = new Bindable();
-
- AddRange(new Drawable[]
- {
- background = new Box
- {
- RelativeSizeAxes = Axes.Both
- },
- new RankingsScopeSelector
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Current = scope,
- }
- });
-
- AddStep(@"Select country", () => scope.Value = RankingsScope.Country);
- AddStep(@"Select performance", () => scope.Value = RankingsScope.Performance);
- AddStep(@"Select score", () => scope.Value = RankingsScope.Score);
- AddStep(@"Select spotlights", () => scope.Value = RankingsScope.Spotlights);
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- background.Colour = colours.GreySeafoam;
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs
new file mode 100644
index 0000000000..f27ab1e775
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs
@@ -0,0 +1,93 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
+using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Rankings;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneRankingsSpotlightSelector : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(SpotlightSelector),
+ };
+
+ protected override bool UseOnlineAPI => true;
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
+ [Resolved]
+ private IAPIProvider api { get; set; }
+
+ private readonly SpotlightSelector selector;
+
+ public TestSceneRankingsSpotlightSelector()
+ {
+ Add(selector = new SpotlightSelector());
+ }
+
+ [Test]
+ public void TestVisibility()
+ {
+ AddStep("Toggle Visibility", selector.ToggleVisibility);
+ }
+
+ [Test]
+ public void TestLocalSpotlights()
+ {
+ var spotlights = new[]
+ {
+ new APISpotlight
+ {
+ Name = "Spotlight 1",
+ StartDate = DateTimeOffset.Now,
+ EndDate = DateTimeOffset.Now,
+ },
+ new APISpotlight
+ {
+ Name = "Spotlight 2",
+ StartDate = DateTimeOffset.Now,
+ EndDate = DateTimeOffset.Now,
+ },
+ new APISpotlight
+ {
+ Name = "Spotlight 3",
+ StartDate = DateTimeOffset.Now,
+ EndDate = DateTimeOffset.Now,
+ },
+ };
+
+ AddStep("load spotlights", () => selector.Spotlights = spotlights);
+ AddStep("change to spotlight 3", () => selector.Current.Value = spotlights[2]);
+ }
+
+ [Test]
+ public void TestOnlineSpotlights()
+ {
+ List spotlights = null;
+
+ AddStep("retrieve spotlights", () =>
+ {
+ var req = new GetSpotlightsRequest();
+ req.Success += res => spotlights = res.Spotlights;
+
+ api.Perform(req);
+ });
+
+ AddStep("set spotlights", () =>
+ {
+ if (spotlights != null)
+ selector.Spotlights = spotlights;
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
index 93da2a439e..656402e713 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
@@ -16,6 +16,7 @@ using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Catch;
using osu.Framework.Allocation;
+using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
{
@@ -36,6 +37,9 @@ namespace osu.Game.Tests.Visual.Online
[Resolved]
private IAPIProvider api { get; set; }
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
private readonly BasicScrollContainer scrollFlow;
private readonly DimmedLoadingLayer loading;
private CancellationTokenSource cancellationToken;
@@ -64,6 +68,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("Mania scores", () => createScoreTable(new ManiaRuleset().RulesetInfo));
AddStep("Taiko country scores", () => createCountryTable(new TaikoRuleset().RulesetInfo));
AddStep("Catch US performance page 10", () => createPerformanceTable(new CatchRuleset().RulesetInfo, "US", 10));
+ AddStep("Osu spotlight table (chart 271)", () => createSpotlightTable(new OsuRuleset().RulesetInfo, 271));
}
private void createCountryTable(RulesetInfo ruleset, int page = 1)
@@ -108,6 +113,20 @@ namespace osu.Game.Tests.Visual.Online
api.Queue(request);
}
+ private void createSpotlightTable(RulesetInfo ruleset, int spotlight)
+ {
+ onLoadStarted();
+
+ request = new GetSpotlightRankingsRequest(ruleset, spotlight);
+ ((GetSpotlightRankingsRequest)request).Success += rankings => Schedule(() =>
+ {
+ var table = new ScoresTable(1, rankings.Users);
+ loadTable(table);
+ });
+
+ api.Queue(request);
+ }
+
private void onLoadStarted()
{
loading.Show();
diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index b19f2dbf31..3c959e05c1 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -3,11 +3,13 @@
using System;
using System.Collections.Generic;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
using osu.Game.Overlays.BeatmapSet.Scores;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
@@ -27,6 +29,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(ScoreTableRowBackground),
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
public TestSceneScoresContainer()
{
TestScoresContainer scoresContainer;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs b/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs
new file mode 100644
index 0000000000..d025a8d7c2
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneSpotlightsLayout.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Rankings;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Catch;
+using osu.Game.Rulesets.Mania;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Taiko;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneSpotlightsLayout : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(SpotlightsLayout),
+ typeof(SpotlightSelector),
+ };
+
+ protected override bool UseOnlineAPI => true;
+
+ [Cached]
+ private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Green);
+
+ public TestSceneSpotlightsLayout()
+ {
+ var ruleset = new Bindable(new OsuRuleset().RulesetInfo);
+
+ Add(new BasicScrollContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Width = 0.8f,
+ Child = new SpotlightsLayout
+ {
+ Ruleset = { BindTarget = ruleset }
+ }
+ });
+
+ AddStep("Osu ruleset", () => ruleset.Value = new OsuRuleset().RulesetInfo);
+ AddStep("Mania ruleset", () => ruleset.Value = new ManiaRuleset().RulesetInfo);
+ AddStep("Taiko ruleset", () => ruleset.Value = new TaikoRuleset().RulesetInfo);
+ AddStep("Catch ruleset", () => ruleset.Value = new CatchRuleset().RulesetInfo);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs b/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs
index 4702d24125..8ecbf0891b 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs
@@ -6,7 +6,9 @@ using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Bindables;
using osu.Game.Overlays.Comments;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
+using osu.Framework.Allocation;
+using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
{
@@ -17,6 +19,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(TotalCommentsCounter),
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
public TestSceneTotalCommentsCounter()
{
var count = new BindableInt();
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
index 63b46c991f..523de4e38f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
@@ -24,13 +24,16 @@ namespace osu.Game.Tests.Visual.Online
typeof(ProfileHeader),
typeof(RankGraph),
typeof(LineGraph),
- typeof(TabControlOverlayHeader.OverlayHeaderTabControl),
+ typeof(TabControlOverlayHeader<>.OverlayHeaderTabControl),
typeof(CentreHeaderContainer),
typeof(BottomHeaderContainer),
typeof(DetailHeaderContainer),
typeof(ProfileHeaderButton)
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
[Resolved]
private IAPIProvider api { get; set; }
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
index f022425bf6..06091f3c81 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileRecentSection.cs
@@ -5,6 +5,7 @@ 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.Shapes;
@@ -12,6 +13,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Recent;
@@ -28,6 +30,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(MedalIcon)
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
+
public TestSceneUserProfileRecentSection()
{
Children = new Drawable[]
@@ -131,6 +136,22 @@ namespace osu.Game.Tests.Visual.Online
Beatmap = dummyBeatmap,
},
new APIRecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.Rank,
+ Rank = 1,
+ Mode = "vitaru",
+ Beatmap = dummyBeatmap,
+ },
+ new APIRecentActivity
+ {
+ User = dummyUser,
+ Type = RecentActivityType.Rank,
+ Rank = 1,
+ Mode = "fruits",
+ Beatmap = dummyBeatmap,
+ },
+ new APIRecentActivity
{
User = dummyUser,
Type = RecentActivityType.RankLost,
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
new file mode 100644
index 0000000000..19b72e7071
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileScores.cs
@@ -0,0 +1,101 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Game.Overlays.Profile.Sections;
+using osu.Game.Overlays.Profile.Sections.Ranks;
+using osu.Framework.Graphics;
+using osu.Game.Scoring;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Overlays;
+using osu.Framework.Allocation;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneUserProfileScores : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(DrawableProfileScore),
+ typeof(DrawableProfileWeightedScore),
+ typeof(ProfileItemContainer),
+ };
+
+ public TestSceneUserProfileScores()
+ {
+ var score = new ScoreInfo
+ {
+ PP = 134.32,
+ Rank = ScoreRank.A,
+ Beatmap = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata
+ {
+ Title = "Triumph & Regret",
+ Artist = "typeMARS"
+ },
+ Version = "[4K] Regret"
+ },
+ Date = DateTimeOffset.Now,
+ Mods = new Mod[]
+ {
+ new OsuModHardRock(),
+ new OsuModDoubleTime(),
+ },
+ Accuracy = 0.998546
+ };
+
+ var noPPScore = new ScoreInfo
+ {
+ Rank = ScoreRank.B,
+ Beatmap = new BeatmapInfo
+ {
+ Metadata = new BeatmapMetadata
+ {
+ Title = "C18H27NO3(extend)",
+ Artist = "Team Grimoire"
+ },
+ Version = "[4K] Cataclysmic Hypernova"
+ },
+ Date = DateTimeOffset.Now,
+ Accuracy = 0.55879
+ };
+
+ Add(new FillFlowContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 10),
+ Children = new[]
+ {
+ new ColourProvidedContainer(OverlayColourScheme.Green, new DrawableProfileScore(score)),
+ new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileScore(noPPScore)),
+ new ColourProvidedContainer(OverlayColourScheme.Pink, new DrawableProfileWeightedScore(score, 0.85))
+ }
+ });
+ }
+
+ private class ColourProvidedContainer : Container
+ {
+ [Cached]
+ private readonly OverlayColourProvider colourProvider;
+
+ public ColourProvidedContainer(OverlayColourScheme colourScheme, DrawableProfileScore score)
+ {
+ colourProvider = new OverlayColourProvider(colourScheme);
+
+ AutoSizeAxes = Axes.Y;
+ RelativeSizeAxes = Axes.X;
+ Add(score);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs
index 2951f6b63e..c8e94b2915 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserRanks.cs
@@ -4,11 +4,13 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
+using osu.Game.Overlays;
using osu.Game.Overlays.Profile.Sections;
using osu.Game.Overlays.Profile.Sections.Ranks;
using osu.Game.Users;
@@ -20,7 +22,15 @@ namespace osu.Game.Tests.Visual.Online
{
protected override bool UseOnlineAPI => true;
- public override IReadOnlyList RequiredTypes => new[] { typeof(DrawableProfileScore), typeof(RanksSection) };
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(DrawableProfileScore),
+ typeof(DrawableProfileWeightedScore),
+ typeof(RanksSection)
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
public TestSceneUserRanks()
{
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
new file mode 100644
index 0000000000..3d3517ada4
--- /dev/null
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs
@@ -0,0 +1,175 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Graphics;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Screens.Select.Details;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.SongSelect
+{
+ [System.ComponentModel.Description("Advanced beatmap statistics display")]
+ public class TestSceneAdvancedStats : OsuTestScene
+ {
+ private TestAdvancedStats advancedStats;
+
+ [Resolved]
+ private RulesetStore rulesets { get; set; }
+
+ [Resolved]
+ private OsuColour colours { get; set; }
+
+ [SetUp]
+ public void Setup() => Schedule(() => Child = advancedStats = new TestAdvancedStats
+ {
+ Width = 500
+ });
+
+ private BeatmapInfo exampleBeatmapInfo => new BeatmapInfo
+ {
+ RulesetID = 0,
+ Ruleset = rulesets.AvailableRulesets.First(),
+ BaseDifficulty = new BeatmapDifficulty
+ {
+ CircleSize = 7.2f,
+ DrainRate = 3,
+ OverallDifficulty = 5.7f,
+ ApproachRate = 3.5f
+ },
+ StarDifficulty = 4.5f
+ };
+
+ [Test]
+ public void TestNoMod()
+ {
+ AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
+
+ AddStep("no mods selected", () => SelectedMods.Value = Array.Empty());
+
+ AddAssert("first bar text is Circle Size", () => advancedStats.ChildrenOfType().First().Text == "Circle Size");
+ AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
+ AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain));
+ AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
+ AddAssert("approach rate bar is white", () => barIsWhite(advancedStats.ApproachRate));
+ }
+
+ [Test]
+ public void TestManiaFirstBarText()
+ {
+ AddStep("set beatmap", () => advancedStats.Beatmap = new BeatmapInfo
+ {
+ Ruleset = rulesets.GetRuleset(3),
+ BaseDifficulty = new BeatmapDifficulty
+ {
+ CircleSize = 5,
+ DrainRate = 4.3f,
+ OverallDifficulty = 4.5f,
+ ApproachRate = 3.1f
+ },
+ StarDifficulty = 8
+ });
+
+ AddAssert("first bar text is Key Count", () => advancedStats.ChildrenOfType().First().Text == "Key Count");
+ }
+
+ [Test]
+ public void TestEasyMod()
+ {
+ AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
+
+ AddStep("select EZ mod", () =>
+ {
+ var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
+ SelectedMods.Value = new[] { ruleset.GetAllMods().OfType().Single() };
+ });
+
+ AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue));
+ AddAssert("HP drain bar is blue", () => barIsBlue(advancedStats.HpDrain));
+ AddAssert("accuracy bar is blue", () => barIsBlue(advancedStats.Accuracy));
+ AddAssert("approach rate bar is blue", () => barIsBlue(advancedStats.ApproachRate));
+ }
+
+ [Test]
+ public void TestHardRockMod()
+ {
+ AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
+
+ AddStep("select HR mod", () =>
+ {
+ var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
+ SelectedMods.Value = new[] { ruleset.GetAllMods().OfType().Single() };
+ });
+
+ AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue));
+ AddAssert("HP drain bar is red", () => barIsRed(advancedStats.HpDrain));
+ AddAssert("accuracy bar is red", () => barIsRed(advancedStats.Accuracy));
+ AddAssert("approach rate bar is red", () => barIsRed(advancedStats.ApproachRate));
+ }
+
+ [Test]
+ public void TestUnchangedDifficultyAdjustMod()
+ {
+ AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
+
+ AddStep("select unchanged Difficulty Adjust mod", () =>
+ {
+ var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
+ var difficultyAdjustMod = ruleset.GetAllMods().OfType().Single();
+ difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty);
+ SelectedMods.Value = new[] { difficultyAdjustMod };
+ });
+
+ AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
+ AddAssert("HP drain bar is white", () => barIsWhite(advancedStats.HpDrain));
+ AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
+ AddAssert("approach rate bar is white", () => barIsWhite(advancedStats.ApproachRate));
+ }
+
+ [Test]
+ public void TestChangedDifficultyAdjustMod()
+ {
+ AddStep("set beatmap", () => advancedStats.Beatmap = exampleBeatmapInfo);
+
+ AddStep("select changed Difficulty Adjust mod", () =>
+ {
+ var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance();
+ var difficultyAdjustMod = ruleset.GetAllMods().OfType().Single();
+ var originalDifficulty = advancedStats.Beatmap.BaseDifficulty;
+ var adjustedDifficulty = new BeatmapDifficulty
+ {
+ CircleSize = originalDifficulty.CircleSize,
+ DrainRate = originalDifficulty.DrainRate - 0.5f,
+ OverallDifficulty = originalDifficulty.OverallDifficulty,
+ ApproachRate = originalDifficulty.ApproachRate + 2.2f,
+ };
+ difficultyAdjustMod.ReadFromDifficulty(adjustedDifficulty);
+ SelectedMods.Value = new[] { difficultyAdjustMod };
+ });
+
+ AddAssert("circle size bar is white", () => barIsWhite(advancedStats.FirstValue));
+ AddAssert("drain rate bar is blue", () => barIsBlue(advancedStats.HpDrain));
+ AddAssert("accuracy bar is white", () => barIsWhite(advancedStats.Accuracy));
+ AddAssert("approach rate bar is red", () => barIsRed(advancedStats.ApproachRate));
+ }
+
+ private bool barIsWhite(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == Color4.White;
+ private bool barIsBlue(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.BlueDark;
+ private bool barIsRed(AdvancedStats.StatisticRow row) => row.ModBar.AccentColour == colours.Red;
+
+ private class TestAdvancedStats : AdvancedStats
+ {
+ public new StatisticRow FirstValue => base.FirstValue;
+ public new StatisticRow HpDrain => base.HpDrain;
+ public new StatisticRow Accuracy => base.Accuracy;
+ public new StatisticRow ApproachRate => base.ApproachRate;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index 132b104afb..71ae47dc66 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -437,6 +437,53 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("Selection was random", () => eagerSelectedIDs.Count > 1);
}
+ [Test]
+ public void TestFilteringByUserStarDifficulty()
+ {
+ BeatmapSetInfo set = null;
+
+ loadBeatmaps(new List());
+
+ AddStep("add mixed difficulty set", () =>
+ {
+ set = createTestBeatmapSet(1);
+ set.Beatmaps.Clear();
+
+ for (int i = 1; i <= 15; i++)
+ {
+ set.Beatmaps.Add(new BeatmapInfo
+ {
+ Version = $"Stars: {i}",
+ StarDifficulty = i,
+ });
+ }
+
+ carousel.UpdateBeatmapSet(set);
+ });
+
+ AddStep("select added set", () => carousel.SelectBeatmap(set.Beatmaps[0], false));
+
+ AddStep("filter [5..]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 5 } }));
+ AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask);
+ checkVisibleItemCount(true, 11);
+
+ AddStep("filter to [0..7]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Max = 7 } }));
+ AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask);
+ checkVisibleItemCount(true, 7);
+
+ AddStep("filter to [5..7]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 5, Max = 7 } }));
+ AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask);
+ checkVisibleItemCount(true, 3);
+
+ AddStep("filter [2..2]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 2, Max = 2 } }));
+ AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask);
+ checkVisibleItemCount(true, 1);
+
+ AddStep("filter to [0..]", () => carousel.Filter(new FilterCriteria { UserStarDifficulty = { Min = 0 } }));
+ AddUntilStep("Wait for debounce", () => !carousel.PendingFilterTask);
+ checkVisibleItemCount(true, 15);
+ }
+
private void loadBeatmaps(List beatmapSets = null)
{
createCarousel();
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
index 6aa5a76490..acf037198f 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapDetails.cs
@@ -3,14 +3,8 @@
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Testing;
using osu.Game.Beatmaps;
-using osu.Game.Graphics;
-using osu.Game.Graphics.UserInterface;
-using osu.Game.Rulesets;
-using osu.Game.Rulesets.Mods;
using osu.Game.Screens.Select;
namespace osu.Game.Tests.Visual.SongSelect
@@ -180,27 +174,5 @@ namespace osu.Game.Tests.Visual.SongSelect
OnlineBeatmapID = 162,
});
}
-
- [Resolved]
- private RulesetStore rulesets { get; set; }
-
- [Resolved]
- private OsuColour colours { get; set; }
-
- [Test]
- public void TestModAdjustments()
- {
- TestAllMetrics();
-
- Ruleset ruleset = rulesets.AvailableRulesets.First().CreateInstance();
-
- AddStep("with EZ mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModEasy) });
-
- AddAssert("first bar coloured blue", () => details.ChildrenOfType().Skip(1).First().AccentColour == colours.BlueDark);
-
- AddStep("with HR mod", () => SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModHardRock) });
-
- AddAssert("first bar coloured red", () => details.ChildrenOfType().Skip(1).First().AccentColour == colours.Red);
- }
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 2b52deb605..3eff75b020 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -3,10 +3,12 @@
using System;
using System.Collections.Generic;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
+using osu.Game.Overlays;
using osu.Game.Online.Placeholders;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
@@ -29,8 +31,16 @@ namespace osu.Game.Tests.Visual.SongSelect
private readonly FailableLeaderboard leaderboard;
+ [Cached]
+ private readonly DialogOverlay dialogOverlay;
+
public TestSceneBeatmapLeaderboard()
{
+ Add(dialogOverlay = new DialogOverlay
+ {
+ Depth = -1
+ });
+
Add(leaderboard = new FailableLeaderboard
{
Origin = Anchor.Centre,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 00fa95bedc..9474c08c5a 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -11,20 +11,24 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Platform;
using osu.Framework.Screens;
+using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Rulesets.Taiko;
+using osu.Game.Screens.Play;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Carousel;
using osu.Game.Screens.Select.Filter;
+using osuTK.Input;
namespace osu.Game.Tests.Visual.SongSelect
{
@@ -70,19 +74,23 @@ namespace osu.Game.Tests.Visual.SongSelect
// required to get bindables attached
Add(music);
- Beatmap.SetDefault();
-
Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
}
private OsuConfigManager config;
- [SetUp]
- public virtual void SetUp() => Schedule(() =>
+ public override void SetUpSteps()
{
- Ruleset.Value = new OsuRuleset().RulesetInfo;
- manager?.Delete(manager.GetAllUsableBeatmapSets());
- });
+ base.SetUpSteps();
+
+ AddStep("delete all beatmaps", () =>
+ {
+ Ruleset.Value = new OsuRuleset().RulesetInfo;
+ manager?.Delete(manager.GetAllUsableBeatmapSets());
+
+ Beatmap.SetDefault();
+ });
+ }
[Test]
public void TestSingleFilterOnEnter()
@@ -95,6 +103,115 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("filter count is 1", () => songSelect.FilterCount == 1);
}
+ [Test]
+ public void TestChangeBeatmapBeforeEnter()
+ {
+ addRulesetImportStep(0);
+
+ createSongSelect();
+
+ AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
+
+ WorkingBeatmap selected = null;
+
+ AddStep("store selected beatmap", () => selected = Beatmap.Value);
+
+ AddStep("select next and enter", () =>
+ {
+ InputManager.PressKey(Key.Down);
+ InputManager.ReleaseKey(Key.Down);
+ InputManager.PressKey(Key.Enter);
+ InputManager.ReleaseKey(Key.Enter);
+ });
+
+ AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
+ AddAssert("ensure selection changed", () => selected != Beatmap.Value);
+ }
+
+ [Test]
+ public void TestChangeBeatmapAfterEnter()
+ {
+ addRulesetImportStep(0);
+
+ createSongSelect();
+
+ AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
+
+ WorkingBeatmap selected = null;
+
+ AddStep("store selected beatmap", () => selected = Beatmap.Value);
+
+ AddStep("select next and enter", () =>
+ {
+ InputManager.PressKey(Key.Enter);
+ InputManager.ReleaseKey(Key.Enter);
+ InputManager.PressKey(Key.Down);
+ InputManager.ReleaseKey(Key.Down);
+ });
+
+ AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
+ AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
+ }
+
+ [Test]
+ public void TestChangeBeatmapViaMouseBeforeEnter()
+ {
+ addRulesetImportStep(0);
+
+ createSongSelect();
+
+ AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
+
+ WorkingBeatmap selected = null;
+
+ AddStep("store selected beatmap", () => selected = Beatmap.Value);
+
+ AddStep("select next and enter", () =>
+ {
+ InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType()
+ .First(b => ((CarouselBeatmap)b.Item).Beatmap != songSelect.Carousel.SelectedBeatmap));
+
+ InputManager.PressButton(MouseButton.Left);
+ InputManager.ReleaseButton(MouseButton.Left);
+
+ InputManager.PressKey(Key.Enter);
+ InputManager.ReleaseKey(Key.Enter);
+ });
+
+ AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
+ AddAssert("ensure selection changed", () => selected != Beatmap.Value);
+ }
+
+ [Test]
+ public void TestChangeBeatmapViaMouseAfterEnter()
+ {
+ addRulesetImportStep(0);
+
+ createSongSelect();
+
+ AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
+
+ WorkingBeatmap selected = null;
+
+ AddStep("store selected beatmap", () => selected = Beatmap.Value);
+
+ AddStep("select next and enter", () =>
+ {
+ InputManager.MoveMouseTo(songSelect.Carousel.ChildrenOfType()
+ .First(b => ((CarouselBeatmap)b.Item).Beatmap != songSelect.Carousel.SelectedBeatmap));
+
+ InputManager.PressButton(MouseButton.Left);
+
+ InputManager.PressKey(Key.Enter);
+ InputManager.ReleaseKey(Key.Enter);
+
+ InputManager.ReleaseButton(MouseButton.Left);
+ });
+
+ AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
+ AddAssert("ensure selection didn't change", () => selected == Beatmap.Value);
+ }
+
[Test]
public void TestNoFilterOnSimpleResume()
{
@@ -310,6 +427,69 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("start not requested", () => !startRequested);
}
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestExternalBeatmapChangeWhileFiltered(bool differentRuleset)
+ {
+ createSongSelect();
+ addManyTestMaps();
+
+ changeRuleset(0);
+
+ AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
+
+ AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nonono");
+
+ AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap);
+
+ AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmap == null);
+
+ BeatmapInfo target = null;
+
+ AddStep("select beatmap externally", () =>
+ {
+ target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == (differentRuleset ? 1 : 0)))
+ .ElementAt(5).Beatmaps.First();
+
+ Beatmap.Value = manager.GetWorkingBeatmap(target);
+ });
+
+ AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
+
+ AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID);
+ AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
+
+ AddStep("reset filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = string.Empty);
+
+ AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
+ AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID);
+ }
+
+ [Test]
+ public void TestAutoplayViaCtrlEnter()
+ {
+ addRulesetImportStep(0);
+
+ createSongSelect();
+
+ AddStep("press ctrl+enter", () =>
+ {
+ InputManager.PressKey(Key.ControlLeft);
+ InputManager.PressKey(Key.Enter);
+
+ InputManager.ReleaseKey(Key.ControlLeft);
+ InputManager.ReleaseKey(Key.Enter);
+ });
+
+ AddUntilStep("wait for player", () => Stack.CurrentScreen is PlayerLoader);
+
+ AddAssert("autoplay enabled", () => songSelect.Mods.Value.FirstOrDefault() is ModAutoplay);
+
+ AddUntilStep("wait for return to ss", () => songSelect.IsCurrentScreen());
+
+ AddAssert("mod disabled", () => songSelect.Mods.Value.Count == 0);
+ }
+
[Test]
public void TestHideSetSelectsCorrectBeatmap()
{
@@ -327,6 +507,7 @@ namespace osu.Game.Tests.Visual.SongSelect
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
private static int importId;
+
private int getImportId() => ++importId;
private void checkMusicPlaying(bool playing) =>
@@ -410,6 +591,8 @@ namespace osu.Game.Tests.Visual.SongSelect
public new Bindable Ruleset => base.Ruleset;
+ public new FilterControl FilterControl => base.FilterControl;
+
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
public new BeatmapCarousel Carousel => base.Carousel;
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs
index e34e1844ce..0598324110 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneUserTopScoreContainer.cs
@@ -1,11 +1,13 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osuTK.Graphics;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays;
using osu.Game.Scoring;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Select.Leaderboards;
@@ -15,10 +17,18 @@ namespace osu.Game.Tests.Visual.SongSelect
{
public class TestSceneUserTopScoreContainer : OsuTestScene
{
+ [Cached]
+ private readonly DialogOverlay dialogOverlay;
+
public TestSceneUserTopScoreContainer()
{
UserTopScoreContainer topScoreContainer;
+ Add(dialogOverlay = new DialogOverlay
+ {
+ Depth = -1
+ });
+
Add(new Container
{
Origin = Anchor.BottomCentre,
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs
index 19eebc89b6..3967b62c95 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs
@@ -1,9 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
@@ -12,11 +14,11 @@ namespace osu.Game.Tests.Visual.UserInterface
[TestFixture]
public class TestSceneBreadcrumbControl : OsuTestScene
{
- private readonly BreadcrumbControl breadcrumbs;
+ private readonly TestBreadcrumbControl breadcrumbs;
public TestSceneBreadcrumbControl()
{
- Add(breadcrumbs = new BreadcrumbControl
+ Add(breadcrumbs = new TestBreadcrumbControl
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -25,8 +27,13 @@ namespace osu.Game.Tests.Visual.UserInterface
});
AddStep(@"first", () => breadcrumbs.Current.Value = BreadcrumbTab.Click);
+ assertVisible(1);
+
AddStep(@"second", () => breadcrumbs.Current.Value = BreadcrumbTab.The);
+ assertVisible(2);
+
AddStep(@"third", () => breadcrumbs.Current.Value = BreadcrumbTab.Circles);
+ assertVisible(3);
}
[BackgroundDependencyLoader]
@@ -35,11 +42,27 @@ namespace osu.Game.Tests.Visual.UserInterface
breadcrumbs.StripColour = colours.Blue;
}
+ private void assertVisible(int count) => AddAssert($"first {count} item(s) visible", () =>
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (breadcrumbs.GetDrawable((BreadcrumbTab)i).State != Visibility.Visible)
+ return false;
+ }
+
+ return true;
+ });
+
private enum BreadcrumbTab
{
Click,
The,
Circles,
}
+
+ private class TestBreadcrumbControl : BreadcrumbControl
+ {
+ public BreadcrumbTabItem GetDrawable(BreadcrumbTab tab) => (BreadcrumbTabItem)TabContainer.First(t => t.Value == tab);
+ }
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
index e95f4c09c6..d1dde4664a 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCursors.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.Sprites;
using osuTK;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
new file mode 100644
index 0000000000..1e5e26e4c5
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -0,0 +1,181 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Cursor;
+using osu.Framework.Platform;
+using osu.Framework.Testing;
+using osu.Framework.Utils;
+using osu.Game.Beatmaps;
+using osu.Game.Graphics.Cursor;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.Leaderboards;
+using osu.Game.Online.Placeholders;
+using osu.Game.Overlays;
+using osu.Game.Rulesets;
+using osu.Game.Scoring;
+using osu.Game.Screens.Select.Leaderboards;
+using osu.Game.Tests.Resources;
+using osu.Game.Users;
+using osuTK;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneDeleteLocalScore : ManualInputManagerTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(Placeholder),
+ typeof(MessagePlaceholder),
+ typeof(RetrievalFailurePlaceholder),
+ typeof(UserTopScoreContainer),
+ typeof(Leaderboard),
+ typeof(LeaderboardScore),
+ };
+
+ private readonly ContextMenuContainer contextMenuContainer;
+ private readonly BeatmapLeaderboard leaderboard;
+
+ private RulesetStore rulesetStore;
+ private BeatmapManager beatmapManager;
+ private ScoreManager scoreManager;
+
+ private readonly List scores = new List();
+ private BeatmapInfo beatmap;
+
+ [Cached]
+ private readonly DialogOverlay dialogOverlay;
+
+ public TestSceneDeleteLocalScore()
+ {
+ Children = new Drawable[]
+ {
+ contextMenuContainer = new OsuContextMenuContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = leaderboard = new BeatmapLeaderboard
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Size = new Vector2(550f, 450f),
+ Scope = BeatmapLeaderboardScope.Local,
+ Beatmap = new BeatmapInfo
+ {
+ ID = 1,
+ Metadata = new BeatmapMetadata
+ {
+ ID = 1,
+ Title = "TestSong",
+ Artist = "TestArtist",
+ Author = new User
+ {
+ Username = "TestAuthor"
+ },
+ },
+ Version = "Insane"
+ },
+ }
+ },
+ dialogOverlay = new DialogOverlay()
+ };
+ }
+
+ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
+ {
+ var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
+
+ dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory));
+ dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, Audio, dependencies.Get(), Beatmap.Default));
+ dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory));
+
+ beatmap = beatmapManager.Import(TestResources.GetTestBeatmapForImport()).Result.Beatmaps[0];
+
+ for (int i = 0; i < 50; i++)
+ {
+ var score = new ScoreInfo
+ {
+ OnlineScoreID = i,
+ Beatmap = beatmap,
+ BeatmapInfoID = beatmap.ID,
+ Accuracy = RNG.NextDouble(),
+ TotalScore = RNG.Next(1, 1000000),
+ MaxCombo = RNG.Next(1, 1000),
+ Rank = ScoreRank.XH,
+ User = new User { Username = "TestUser" },
+ };
+
+ scores.Add(scoreManager.Import(score).Result);
+ }
+
+ scores.Sort(Comparer.Create((s1, s2) => s2.TotalScore.CompareTo(s1.TotalScore)));
+
+ return dependencies;
+ }
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
+ // Due to soft deletions, we can re-use deleted scores between test runs
+ scoreManager.Undelete(scoreManager.QueryScores(s => s.DeletePending).ToList());
+
+ leaderboard.Scores = null;
+ leaderboard.FinishTransforms(true); // After setting scores, we may be waiting for transforms to expire drawables
+
+ leaderboard.Beatmap = beatmap;
+ leaderboard.RefreshScores(); // Required in the case that the beatmap hasn't changed
+ });
+
+ [SetUpSteps]
+ public void SetupSteps()
+ {
+ // Ensure the leaderboard has finished async-loading drawables
+ AddUntilStep("wait for drawables", () => leaderboard.ChildrenOfType().Any());
+
+ // Ensure the leaderboard items have finished showing up
+ AddStep("finish transforms", () => leaderboard.FinishTransforms(true));
+ }
+
+ [Test]
+ public void TestDeleteViaRightClick()
+ {
+ AddStep("open menu for top score", () =>
+ {
+ InputManager.MoveMouseTo(leaderboard.ChildrenOfType().First());
+ InputManager.Click(MouseButton.Right);
+ });
+
+ // Ensure the context menu has finished showing
+ AddStep("finish transforms", () => contextMenuContainer.FinishTransforms(true));
+
+ AddStep("click delete option", () =>
+ {
+ InputManager.MoveMouseTo(contextMenuContainer.ChildrenOfType().First(i => i.Item.Text.Value.ToLowerInvariant() == "delete"));
+ InputManager.Click(MouseButton.Left);
+ });
+
+ // Ensure the dialog has finished showing
+ AddStep("finish transforms", () => dialogOverlay.FinishTransforms(true));
+
+ AddStep("click delete button", () =>
+ {
+ InputManager.MoveMouseTo(dialogOverlay.ChildrenOfType().First());
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != scores[0].OnlineScoreID));
+ }
+
+ [Test]
+ public void TestDeleteViaDatabase()
+ {
+ AddStep("delete top score", () => scoreManager.Delete(scores[0]));
+ AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != scores[0].OnlineScoreID));
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
index 6eb621ca3b..63197ed26a 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFooterButtonMods.cs
@@ -16,7 +16,8 @@ namespace osu.Game.Tests.Visual.UserInterface
{
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(FooterButtonMods)
+ typeof(FooterButtonMods),
+ typeof(FooterButton)
};
private readonly TestFooterButtonMods footerButtonMods;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs
index 54876dbbda..4e394b5ed8 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLogoTrackingContainer.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Testing;
using osu.Game.Graphics.Containers;
using osu.Game.Screens.Menu;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs
new file mode 100644
index 0000000000..443cf59003
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModButton.cs
@@ -0,0 +1,62 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Overlays.Mods;
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneModButton : OsuTestScene
+ {
+ public TestSceneModButton()
+ {
+ Children = new Drawable[]
+ {
+ new ModButton(new MultiMod(new TestMod1(), new TestMod2(), new TestMod3(), new TestMod4()))
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre
+ }
+ };
+ }
+
+ private class TestMod1 : TestMod
+ {
+ public override string Name => "Test mod 1";
+
+ public override string Acronym => "M1";
+ }
+
+ private class TestMod2 : TestMod
+ {
+ public override string Name => "Test mod 2";
+
+ public override string Acronym => "M2";
+
+ public override IconUsage? Icon => FontAwesome.Solid.Exclamation;
+ }
+
+ private class TestMod3 : TestMod
+ {
+ public override string Name => "Test mod 3";
+
+ public override string Acronym => "M3";
+
+ public override IconUsage? Icon => FontAwesome.Solid.ArrowRight;
+ }
+
+ private class TestMod4 : TestMod
+ {
+ public override string Name => "Test mod 4";
+
+ public override string Acronym => "M4";
+ }
+
+ private abstract class TestMod : Mod, IApplicableMod
+ {
+ public override double ScoreMultiplier => 1.0;
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
new file mode 100644
index 0000000000..8168faa106
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDisplay.cs
@@ -0,0 +1,40 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Screens.Play.HUD;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneModDisplay : OsuTestScene
+ {
+ [TestCase(ExpansionMode.ExpandOnHover)]
+ [TestCase(ExpansionMode.AlwaysExpanded)]
+ [TestCase(ExpansionMode.AlwaysContracted)]
+ public void TestMode(ExpansionMode mode)
+ {
+ AddStep("create mod display", () =>
+ {
+ Child = new ModDisplay
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ ExpansionMode = mode,
+ Current =
+ {
+ Value = new Mod[]
+ {
+ new OsuModHardRock(),
+ new OsuModDoubleTime(),
+ new OsuModDifficultyAdjust(),
+ new OsuModEasy(),
+ }
+ }
+ };
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
index 12ee4ceb2e..d56324dbe8 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs
@@ -60,9 +60,9 @@ namespace osu.Game.Tests.Visual.UserInterface
{
modSelect = new TestModSelectOverlay
{
- RelativeSizeAxes = Axes.X,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
+ SelectedMods = { BindTarget = SelectedMods }
},
modDisplay = new ModDisplay
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs
index 8dcb7dcbf8..7ff463361a 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs
@@ -25,12 +25,21 @@ namespace osu.Game.Tests.Visual.UserInterface
private readonly Mod testCustomisableMod = new TestModCustomisable1();
+ private readonly Mod testCustomisableAutoOpenMod = new TestModCustomisable2();
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
+ SelectedMods.Value = Array.Empty();
+ Ruleset.Value = new TestRulesetInfo();
+ });
+
[Test]
public void TestButtonShowsOnCustomisableMod()
{
createModSelect();
+ openModSelect();
- AddStep("open", () => modSelect.Show());
AddAssert("button disabled", () => !modSelect.CustomiseButton.Enabled.Value);
AddUntilStep("wait for button load", () => modSelect.ButtonsLoaded);
AddStep("select mod", () => modSelect.SelectMod(testCustomisableMod));
@@ -49,25 +58,42 @@ namespace osu.Game.Tests.Visual.UserInterface
AddAssert("mods still active", () => SelectedMods.Value.Count == 1);
- AddStep("open", () => modSelect.Show());
+ openModSelect();
AddAssert("button enabled", () => modSelect.CustomiseButton.Enabled.Value);
}
+ [Test]
+ public void TestCustomisationMenuVisibility()
+ {
+ createModSelect();
+ openModSelect();
+
+ AddAssert("Customisation closed", () => modSelect.ModSettingsContainer.Alpha == 0);
+ AddStep("select mod", () => modSelect.SelectMod(testCustomisableAutoOpenMod));
+ AddAssert("Customisation opened", () => modSelect.ModSettingsContainer.Alpha == 1);
+ AddStep("deselect mod", () => modSelect.SelectMod(testCustomisableAutoOpenMod));
+ AddAssert("Customisation closed", () => modSelect.ModSettingsContainer.Alpha == 0);
+ }
+
private void createModSelect()
{
AddStep("create mod select", () =>
{
- Ruleset.Value = new TestRulesetInfo();
-
Child = modSelect = new TestModSelectOverlay
{
- RelativeSizeAxes = Axes.X,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
+ SelectedMods = { BindTarget = SelectedMods }
};
});
}
+ private void openModSelect()
+ {
+ AddStep("open", () => modSelect.Show());
+ AddUntilStep("wait for ready", () => modSelect.State.Value == Visibility.Visible && modSelect.ButtonsLoaded);
+ }
+
private class TestModSelectOverlay : ModSelectOverlay
{
public new Container ModSettingsContainer => base.ModSettingsContainer;
@@ -128,6 +154,8 @@ namespace osu.Game.Tests.Visual.UserInterface
public override string Name => "Customisable Mod 2";
public override string Acronym => "CM2";
+
+ public override bool RequiresConfiguration => true;
}
private abstract class TestModCustomisable : Mod, IApplicableMod
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs
index 35e5f9719c..f8ace73168 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNotificationOverlay.cs
@@ -8,7 +8,7 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs
index 330ccecd54..2ea9aec50a 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs
@@ -4,7 +4,7 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Overlays;
using osu.Game.Rulesets.Osu;
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs
new file mode 100644
index 0000000000..1cd68d1fdd
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs
@@ -0,0 +1,165 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Framework.Allocation;
+using osu.Game.Graphics.UserInterface;
+using osu.Framework.Graphics.Shapes;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneOverlayHeader : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OverlayHeader),
+ typeof(TabControlOverlayHeader<>),
+ typeof(BreadcrumbControlOverlayHeader),
+ typeof(TestNoControlHeader),
+ typeof(TestStringTabControlHeader),
+ typeof(TestEnumTabControlHeader),
+ typeof(TestBreadcrumbControlHeader),
+ typeof(OverlayHeaderBackground)
+ };
+
+ private readonly FillFlowContainer flow;
+
+ public TestSceneOverlayHeader()
+ {
+ AddRange(new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ },
+ new BasicScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = flow = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical
+ }
+ }
+ });
+
+ addHeader("Orange OverlayHeader (no background)", new TestNoBackgroundHeader(), OverlayColourScheme.Orange);
+ addHeader("Blue OverlayHeader", new TestNoControlHeader(), OverlayColourScheme.Blue);
+ addHeader("Green TabControlOverlayHeader (string) with ruleset selector", new TestStringTabControlHeader(), OverlayColourScheme.Green);
+ addHeader("Pink TabControlOverlayHeader (enum)", new TestEnumTabControlHeader(), OverlayColourScheme.Pink);
+ addHeader("Red BreadcrumbControlOverlayHeader (no background)", new TestBreadcrumbControlHeader(), OverlayColourScheme.Red);
+ }
+
+ private void addHeader(string name, OverlayHeader header, OverlayColourScheme colourScheme)
+ {
+ flow.Add(new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Margin = new MarginPadding(20),
+ Text = name,
+ },
+ new ColourProvidedContainer(colourScheme, header)
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ }
+ }
+ });
+ }
+
+ private class ColourProvidedContainer : Container
+ {
+ [Cached]
+ private readonly OverlayColourProvider colourProvider;
+
+ public ColourProvidedContainer(OverlayColourScheme colourScheme, OverlayHeader header)
+ {
+ colourProvider = new OverlayColourProvider(colourScheme);
+
+ AutoSizeAxes = Axes.Y;
+ RelativeSizeAxes = Axes.X;
+ Add(header);
+ }
+ }
+
+ private class TestNoBackgroundHeader : OverlayHeader
+ {
+ protected override ScreenTitle CreateTitle() => new TestTitle();
+ }
+
+ private class TestNoControlHeader : OverlayHeader
+ {
+ protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/changelog");
+
+ protected override ScreenTitle CreateTitle() => new TestTitle();
+ }
+
+ private class TestStringTabControlHeader : TabControlOverlayHeader
+ {
+ protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/news");
+
+ protected override ScreenTitle CreateTitle() => new TestTitle();
+
+ protected override Drawable CreateTitleContent() => new OverlayRulesetSelector();
+
+ public TestStringTabControlHeader()
+ {
+ TabControl.AddItem("tab1");
+ TabControl.AddItem("tab2");
+ }
+ }
+
+ private class TestEnumTabControlHeader : TabControlOverlayHeader
+ {
+ protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/rankings");
+
+ protected override ScreenTitle CreateTitle() => new TestTitle();
+ }
+
+ private enum TestEnum
+ {
+ Some,
+ Cool,
+ Tabs
+ }
+
+ private class TestBreadcrumbControlHeader : BreadcrumbControlOverlayHeader
+ {
+ protected override ScreenTitle CreateTitle() => new TestTitle();
+
+ public TestBreadcrumbControlHeader()
+ {
+ TabControl.AddItem("tab1");
+ TabControl.AddItem("tab2");
+ TabControl.Current.Value = "tab2";
+ }
+ }
+
+ private class TestTitle : ScreenTitle
+ {
+ public TestTitle()
+ {
+ Title = "title";
+ Section = "section";
+ }
+
+ protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/changelog");
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs
new file mode 100644
index 0000000000..5a0b28e24a
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeaderBackground.cs
@@ -0,0 +1,42 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneOverlayHeaderBackground : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OverlayHeaderBackground)
+ };
+
+ public TestSceneOverlayHeaderBackground()
+ {
+ Add(new BasicScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 20),
+ Children = new[]
+ {
+ new OverlayHeaderBackground(@"Headers/changelog"),
+ new OverlayHeaderBackground(@"Headers/news"),
+ new OverlayHeaderBackground(@"Headers/rankings"),
+ new OverlayHeaderBackground(@"Headers/search"),
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs
new file mode 100644
index 0000000000..8a98127793
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs
@@ -0,0 +1,82 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Catch;
+using osu.Game.Rulesets.Mania;
+using osu.Game.Rulesets.Osu;
+using osu.Game.Rulesets.Taiko;
+using osu.Framework.Bindables;
+using osu.Game.Overlays;
+using osu.Game.Rulesets;
+using NUnit.Framework;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+using osu.Framework.Allocation;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneOverlayRulesetSelector : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(OverlayRulesetSelector),
+ typeof(OverlayRulesetTabItem),
+ };
+
+ private readonly OverlayRulesetSelector selector;
+ private readonly Bindable ruleset = new Bindable();
+
+ public TestSceneOverlayRulesetSelector()
+ {
+ Add(new FillFlowContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ Children = new[]
+ {
+ new ColourProvidedContainer(OverlayColourScheme.Green, selector = new OverlayRulesetSelector { Current = ruleset }),
+ new ColourProvidedContainer(OverlayColourScheme.Blue, new OverlayRulesetSelector { Current = ruleset }),
+ new ColourProvidedContainer(OverlayColourScheme.Orange, new OverlayRulesetSelector { Current = ruleset }),
+ new ColourProvidedContainer(OverlayColourScheme.Pink, new OverlayRulesetSelector { Current = ruleset }),
+ new ColourProvidedContainer(OverlayColourScheme.Purple, new OverlayRulesetSelector { Current = ruleset }),
+ new ColourProvidedContainer(OverlayColourScheme.Red, new OverlayRulesetSelector { Current = ruleset }),
+ }
+ });
+ }
+
+ private class ColourProvidedContainer : Container
+ {
+ [Cached]
+ private readonly OverlayColourProvider colourProvider;
+
+ public ColourProvidedContainer(OverlayColourScheme colourScheme, OverlayRulesetSelector rulesetSelector)
+ {
+ colourProvider = new OverlayColourProvider(colourScheme);
+ AutoSizeAxes = Axes.Both;
+ Add(rulesetSelector);
+ }
+ }
+
+ [Test]
+ public void TestSelection()
+ {
+ AddStep("Select osu!", () => ruleset.Value = new OsuRuleset().RulesetInfo);
+ AddAssert("Check osu! selected", () => selector.Current.Value.Equals(new OsuRuleset().RulesetInfo));
+
+ AddStep("Select mania", () => ruleset.Value = new ManiaRuleset().RulesetInfo);
+ AddAssert("Check mania selected", () => selector.Current.Value.Equals(new ManiaRuleset().RulesetInfo));
+
+ AddStep("Select taiko", () => ruleset.Value = new TaikoRuleset().RulesetInfo);
+ AddAssert("Check taiko selected", () => selector.Current.Value.Equals(new TaikoRuleset().RulesetInfo));
+
+ AddStep("Select catch", () => ruleset.Value = new CatchRuleset().RulesetInfo);
+ AddAssert("Check catch selected", () => selector.Current.Value.Equals(new CatchRuleset().RulesetInfo));
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs
new file mode 100644
index 0000000000..7476b52b49
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs
@@ -0,0 +1,66 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Utils;
+using osu.Game.Beatmaps;
+using osu.Game.Overlays.Music;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestScenePlaylistOverlay : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(PlaylistOverlay),
+ typeof(Playlist)
+ };
+
+ private readonly BindableList beatmapSets = new BindableList();
+
+ [SetUp]
+ public void Setup() => Schedule(() =>
+ {
+ PlaylistOverlay overlay;
+
+ Child = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(300, 500),
+ Child = overlay = new PlaylistOverlay
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.X,
+ State = { Value = Visibility.Visible }
+ }
+ };
+
+ beatmapSets.Clear();
+
+ for (int i = 0; i < 100; i++)
+ {
+ beatmapSets.Add(new BeatmapSetInfo
+ {
+ Metadata = new BeatmapMetadata
+ {
+ // Create random metadata, then we can check if sorting works based on these
+ Artist = "Some Artist " + RNG.Next(0, 9),
+ Title = $"Some Song {i + 1}",
+ AuthorString = "Some Guy " + RNG.Next(0, 9),
+ },
+ DateAdded = DateTimeOffset.UtcNow,
+ });
+ }
+
+ overlay.BeatmapSets.BindTo(beatmapSets);
+ });
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
index 0cb8683d72..77a7d819a9 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd