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/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/osu.Android.props b/osu.Android.props
index 0b41d5cda4..9c0da1e9fd 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.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/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index dc8df28e6a..e5c3647f99 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -135,6 +135,8 @@ namespace osu.Game.Rulesets.Catch
public override string ShortName => SHORT_NAME;
+ public override string PlayingVerb => "Catching fruit";
+
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetCatch };
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
index 374dd50c11..fc030877f1 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchBananaJudgement.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
return 0;
case HitResult.Perfect:
- return 0.008;
+ return 0.01;
}
}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
index f1399bb5c0..e87ecba749 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchDropletJudgement.cs
@@ -18,17 +18,5 @@ namespace osu.Game.Rulesets.Catch.Judgements
return 30;
}
}
-
- protected override double HealthIncreaseFor(HitResult result)
- {
- switch (result)
- {
- default:
- return base.HealthIncreaseFor(result);
-
- case HitResult.Perfect:
- return 0.007;
- }
- }
}
}
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
index 8fd9ac92ba..2149ed9712 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchJudgement.cs
@@ -23,18 +23,6 @@ namespace osu.Game.Rulesets.Catch.Judgements
}
}
- protected override double HealthIncreaseFor(HitResult result)
- {
- switch (result)
- {
- default:
- return -0.02;
-
- case HitResult.Perfect:
- return 0.01;
- }
- }
-
///
/// Whether fruit on the platter should explode or drop.
/// Note that this is only checked if the owning object is also
diff --git a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
index 3829b5e94f..d607b49ea4 100644
--- a/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
+++ b/osu.Game.Rulesets.Catch/Judgements/CatchTinyDropletJudgement.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Judgements
return 0;
case HitResult.Perfect:
- return 0.004;
+ return 0.02;
}
}
}
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/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/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 2d6ce02e45..0c8c483048 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;
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/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/Judgements/HoldNoteTickJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
index b9c6e3a7f7..00b839f8ec 100644
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/HoldNoteTickJudgement.cs
@@ -15,11 +15,11 @@ namespace osu.Game.Rulesets.Mania.Judgements
{
switch (result)
{
- case HitResult.Miss:
+ default:
return 0;
- default:
- return 0.040;
+ case HitResult.Perfect:
+ return 0.01;
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
index 0e4c811945..c2f8fb8678 100644
--- a/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
+++ b/osu.Game.Rulesets.Mania/Judgements/ManiaJudgement.cs
@@ -29,32 +29,5 @@ namespace osu.Game.Rulesets.Mania.Judgements
return 300;
}
}
-
- protected override double HealthIncreaseFor(HitResult result)
- {
- switch (result)
- {
- case HitResult.Miss:
- return -0.125;
-
- case HitResult.Meh:
- return 0.005;
-
- case HitResult.Ok:
- return 0.010;
-
- case HitResult.Good:
- return 0.035;
-
- case HitResult.Great:
- return 0.055;
-
- case HitResult.Perfect:
- return 0.065;
-
- default:
- return 0;
- }
- }
}
}
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index c50f4314a3..02c2158383 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -179,6 +179,8 @@ namespace osu.Game.Rulesets.Mania
public override string ShortName => SHORT_NAME;
+ public override string PlayingVerb => "Smashing keys";
+
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetMania };
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new ManiaDifficultyCalculator(this, beatmap);
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/Pieces/GlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
deleted file mode 100644
index 1d25a0c966..0000000000
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/GlowPiece.cs
+++ /dev/null
@@ -1,68 +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 osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
-using osuTK.Graphics;
-
-namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
-{
- public class GlowPiece : CompositeDrawable, IHasAccentColour
- {
- private const float glow_alpha = 0.7f;
- private const float glow_radius = 5;
-
- public GlowPiece()
- {
- RelativeSizeAxes = Axes.Both;
- Masking = true;
-
- InternalChild = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0,
- AlwaysPresent = true
- };
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- updateGlow();
- }
-
- private Color4 accentColour;
-
- public Color4 AccentColour
- {
- get => accentColour;
- set
- {
- if (accentColour == value)
- return;
-
- accentColour = value;
-
- updateGlow();
- }
- }
-
- private void updateGlow()
- {
- if (!IsLoaded)
- return;
-
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Glow,
- Colour = AccentColour.Opacity(glow_alpha),
- Radius = glow_radius,
- Hollow = true
- };
- }
- }
-}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
deleted file mode 100644
index 48c7ea7b7f..0000000000
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/LaneGlowPiece.cs
+++ /dev/null
@@ -1,85 +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 osuTK.Graphics;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Colour;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
-
-namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
-{
- public class LaneGlowPiece : CompositeDrawable, IHasAccentColour
- {
- private const float total_height = 100;
- private const float glow_height = 50;
- private const float glow_alpha = 0.4f;
- private const float edge_alpha = 0.3f;
-
- public LaneGlowPiece()
- {
- BypassAutoSizeAxes = Axes.Both;
- RelativeSizeAxes = Axes.X;
- Height = total_height;
-
- InternalChildren = new[]
- {
- new Container
- {
- Name = "Left edge",
- RelativeSizeAxes = Axes.Y,
- Width = 1,
- Children = createGradient(edge_alpha)
- },
- new Container
- {
- Name = "Right edge",
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- RelativeSizeAxes = Axes.Y,
- Width = 1,
- Children = createGradient(edge_alpha)
- },
- new Container
- {
- Name = "Glow",
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.X,
- Height = glow_height,
- Children = createGradient(glow_alpha)
- }
- };
- }
-
- private Drawable[] createGradient(float alpha) => new Drawable[]
- {
- new Box
- {
- Name = "Top",
- RelativeSizeAxes = Axes.Both,
- Height = 0.5f,
- Blending = BlendingParameters.Additive,
- Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha))
- },
- new Box
- {
- Name = "Bottom",
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
- RelativeSizeAxes = Axes.Both,
- Height = 0.5f,
- Blending = BlendingParameters.Additive,
- Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent)
- }
- };
-
- public Color4 AccentColour
- {
- get => Colour;
- set => Colour = value;
- }
- }
-}
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/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/SkinnableTestScene.cs b/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs
index 2fad3bd04f..d4c3000d3f 100644
--- a/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs
+++ b/osu.Game.Rulesets.Osu.Tests/SkinnableTestScene.cs
@@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[BackgroundDependencyLoader]
private void load(AudioManager audio, SkinManager skinManager)
{
- var dllStore = new DllResourceStore("osu.Game.Rulesets.Osu.Tests.dll");
+ var dllStore = new DllResourceStore(typeof(SkinnableTestScene).Assembly);
metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore(dllStore, "Resources/metrics_skin"), audio, true);
defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
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/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 9d4e016eae..1d8c4708c1 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
@@ -4,7 +4,7 @@
-
+
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/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/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
index b81d94a673..20b31c68f2 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,16 +34,7 @@ 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();
@@ -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/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/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/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 36346eb78a..148869f5e8 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -175,6 +175,8 @@ namespace osu.Game.Rulesets.Osu
public override string ShortName => SHORT_NAME;
+ public override string PlayingVerb => "Clicking circles";
+
public override RulesetSettingsSubsection CreateSettings() => new OsuSettingsSubsection(this);
public override ISkin CreateLegacySkinProvider(ISkinSource source) => new OsuLegacySkinTransformer(source);
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.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/Audio/DrumSampleMapping.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs
index aaf113f216..c31b07344d 100644
--- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs
+++ b/osu.Game.Rulesets.Taiko/Audio/DrumSampleMapping.cs
@@ -26,10 +26,6 @@ namespace osu.Game.Rulesets.Taiko.Audio
var centre = s.GetSampleInfo();
var rim = s.GetSampleInfo(HitSampleInfo.HIT_CLAP);
- // todo: this is ugly
- centre.Namespace = "taiko";
- rim.Namespace = "taiko";
-
mappings[s.Time] = new DrumSample
{
Centre = addSound(centre),
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/DrawableTaikoHitObject.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
index 2da5a9c403..b9d31ff906 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableTaikoHitObject.cs
@@ -166,8 +166,6 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
// Normal and clap samples are handled by the drum
protected override IEnumerable GetSamples() => HitObject.Samples.Where(s => s.Name != HitSampleInfo.HIT_NORMAL && s.Name != HitSampleInfo.HIT_CLAP);
- protected override string SampleNamespace => "taiko";
-
protected virtual TaikoPiece CreateMainPiece() => new CirclePiece();
///
diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs
index 4b234b56d4..48eb33976e 100644
--- a/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs
+++ b/osu.Game.Rulesets.Taiko/Replays/TaikoAutoGenerator.cs
@@ -121,41 +121,13 @@ namespace osu.Game.Rulesets.Taiko.Replays
var nextHitObject = GetNextObject(i); // Get the next object that requires pressing the same button
bool canDelayKeyUp = nextHitObject == null || nextHitObject.StartTime > endTime + KEY_UP_DELAY;
-
double calculatedDelay = canDelayKeyUp ? KEY_UP_DELAY : (nextHitObject.StartTime - endTime) * 0.9;
-
Frames.Add(new TaikoReplayFrame(endTime + calculatedDelay));
- if (i < Beatmap.HitObjects.Count - 1)
- {
- double waitTime = Beatmap.HitObjects[i + 1].StartTime - 1000;
- if (waitTime > endTime)
- Frames.Add(new TaikoReplayFrame(waitTime));
- }
-
hitButton = !hitButton;
}
return Replay;
}
-
- protected override HitObject GetNextObject(int currentIndex)
- {
- Type desiredType = Beatmap.HitObjects[currentIndex].GetType();
-
- for (int i = currentIndex + 1; i < Beatmap.HitObjects.Count; i++)
- {
- var currentObj = Beatmap.HitObjects[i];
-
- if (currentObj.GetType() == desiredType ||
- // Un-press all keys before a DrumRoll or Swell
- currentObj is DrumRoll || currentObj is Swell)
- {
- return Beatmap.HitObjects[i];
- }
- }
-
- return null;
- }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitclap.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitclap.wav
new file mode 100755
index 0000000000..9ea2be5855
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitclap.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitfinish.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitfinish.wav
new file mode 100755
index 0000000000..af270ae12a
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitfinish.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitnormal.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitnormal.wav
new file mode 100755
index 0000000000..3d8024c6ae
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitnormal.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitwhistle.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitwhistle.wav
new file mode 100755
index 0000000000..16d254cc87
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/normal-hitwhistle.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitclap.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitclap.wav
new file mode 100755
index 0000000000..b4cfa26265
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitclap.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitfinish.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitfinish.wav
new file mode 100755
index 0000000000..97804a5a61
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitfinish.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitnormal.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitnormal.wav
new file mode 100755
index 0000000000..67f02877a8
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitnormal.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitwhistle.wav b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitwhistle.wav
new file mode 100755
index 0000000000..10206cd228
Binary files /dev/null and b/osu.Game.Rulesets.Taiko/Resources/Samples/Gameplay/soft-hitwhistle.wav differ
diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
new file mode 100644
index 0000000000..381cd14cd4
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.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.Collections.Generic;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
+using osu.Game.Skinning;
+
+namespace osu.Game.Rulesets.Taiko.Skinning
+{
+ public class TaikoLegacySkinTransformer : ISkin
+ {
+ private readonly ISkinSource source;
+
+ public TaikoLegacySkinTransformer(ISkinSource source)
+ {
+ this.source = source;
+ }
+
+ public Drawable GetDrawableComponent(ISkinComponent component) => source.GetDrawableComponent(component);
+
+ public Texture GetTexture(string componentName) => source.GetTexture(componentName);
+
+ public SampleChannel GetSample(ISampleInfo sampleInfo) => source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
+
+ public IBindable GetConfig(TLookup lookup) => source.GetConfig(lookup);
+
+ private class LegacyTaikoSampleInfo : ISampleInfo
+ {
+ private readonly ISampleInfo source;
+
+ public LegacyTaikoSampleInfo(ISampleInfo source)
+ {
+ this.source = source;
+ }
+
+ public IEnumerable LookupNames
+ {
+ get
+ {
+ foreach (var name in source.LookupNames)
+ yield return $"taiko-{name}";
+
+ foreach (var name in source.LookupNames)
+ yield return name;
+ }
+ }
+
+ public int Volume => source.Volume;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
index 777b68a993..fc79e59864 100644
--- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
@@ -21,6 +21,8 @@ using osu.Game.Rulesets.Taiko.Difficulty;
using osu.Game.Rulesets.Taiko.Scoring;
using osu.Game.Scoring;
using System;
+using osu.Game.Rulesets.Taiko.Skinning;
+using osu.Game.Skinning;
namespace osu.Game.Rulesets.Taiko
{
@@ -34,6 +36,8 @@ namespace osu.Game.Rulesets.Taiko
public override IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap) => new TaikoBeatmapConverter(beatmap, this);
+ public override ISkin CreateLegacySkinProvider(ISkinSource source) => new TaikoLegacySkinTransformer(source);
+
public const string SHORT_NAME = "taiko";
public override IEnumerable GetDefaultKeyBindings(int variant = 0) => new[]
@@ -135,6 +139,8 @@ namespace osu.Game.Rulesets.Taiko
public override string ShortName => SHORT_NAME;
+ public override string PlayingVerb => "Bashing drums";
+
public override Drawable CreateIcon() => new SpriteIcon { Icon = OsuIcon.RulesetTaiko };
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new TaikoDifficultyCalculator(this, beatmap);
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/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/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
new file mode 100644
index 0000000000..84506739ab
--- /dev/null
+++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs
@@ -0,0 +1,76 @@
+// 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 System.IO;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
+using osu.Framework.IO.Stores;
+using osu.Framework.Testing;
+using osu.Game.Audio;
+using osu.Game.Skinning;
+using osu.Game.Tests.Resources;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Tests.Gameplay
+{
+ [HeadlessTest]
+ public class TestSceneStoryboardSamples : OsuTestScene
+ {
+ [Test]
+ public void TestRetrieveTopLevelSample()
+ {
+ ISkin skin = null;
+ SampleChannel channel = null;
+
+ AddStep("create skin", () => skin = new TestSkin("test-sample", Audio));
+ AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample")));
+
+ AddAssert("sample is non-null", () => channel != null);
+ }
+
+ [Test]
+ public void TestRetrieveSampleInSubFolder()
+ {
+ ISkin skin = null;
+ SampleChannel channel = null;
+
+ AddStep("create skin", () => skin = new TestSkin("folder/test-sample", Audio));
+ AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample")));
+
+ AddAssert("sample is non-null", () => channel != null);
+ }
+
+ private class TestSkin : LegacySkin
+ {
+ public TestSkin(string resourceName, AudioManager audioManager)
+ : base(DefaultLegacySkin.Info, new TestResourceStore(resourceName), audioManager, "skin.ini")
+ {
+ }
+ }
+
+ private class TestResourceStore : IResourceStore
+ {
+ private readonly string resourceName;
+
+ public TestResourceStore(string resourceName)
+ {
+ this.resourceName = resourceName;
+ }
+
+ public byte[] Get(string name) => name == resourceName ? TestResources.GetStore().Get("Resources/test-sample.mp3") : null;
+
+ public Task GetAsync(string name) => name == resourceName ? TestResources.GetStore().GetAsync("Resources/test-sample.mp3") : null;
+
+ public Stream GetStream(string name) => name == resourceName ? TestResources.GetStore().GetStream("Resources/test-sample.mp3") : null;
+
+ public IEnumerable GetAvailableResources() => new[] { resourceName };
+
+ public void Dispose()
+ {
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tests/Online/TestSceneBeatmapManager.cs b/osu.Game.Tests/Online/TestSceneBeatmapManager.cs
new file mode 100644
index 0000000000..0ae0186770
--- /dev/null
+++ b/osu.Game.Tests/Online/TestSceneBeatmapManager.cs
@@ -0,0 +1,51 @@
+// 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.Testing;
+using osu.Game.Beatmaps;
+using osu.Game.Overlays.Notifications;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Tests.Online
+{
+ [HeadlessTest]
+ public class TestSceneBeatmapManager : OsuTestScene
+ {
+ private BeatmapManager beatmaps;
+ private ProgressNotification recentNotification;
+
+ private static readonly BeatmapSetInfo test_model = new BeatmapSetInfo { OnlineBeatmapSetID = 1 };
+
+ [BackgroundDependencyLoader]
+ private void load(BeatmapManager beatmaps)
+ {
+ this.beatmaps = beatmaps;
+
+ beatmaps.PostNotification = n => recentNotification = n as ProgressNotification;
+ }
+
+ [Test]
+ public void TestCancelDownloadFromRequest()
+ {
+ AddStep("download beatmap", () => beatmaps.Download(test_model));
+
+ AddStep("cancel download from request", () => beatmaps.GetExistingDownload(test_model).Cancel());
+
+ AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_model) == null);
+ AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled);
+ }
+
+ [Test]
+ public void TestCancelDownloadFromNotification()
+ {
+ AddStep("download beatmap", () => beatmaps.Download(test_model));
+
+ AddStep("cancel download from notification", () => recentNotification.Close());
+
+ AddUntilStep("is removed from download list", () => beatmaps.GetExistingDownload(test_model) == null);
+ AddAssert("is notification cancelled", () => recentNotification.State == ProgressNotificationState.Cancelled);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus.osz b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus.osz
new file mode 100644
index 0000000000..987dbea6db
Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus.osz differ
diff --git a/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus_virtual.osz b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus_virtual.osz
new file mode 100644
index 0000000000..8a92423d35
Binary files /dev/null and b/osu.Game.Tests/Resources/Archives/241526 Soleily - Renatus_virtual.osz differ
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index a57405628a..8b892fbb2f 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -9,11 +9,11 @@ namespace osu.Game.Tests.Resources
{
public static class TestResources
{
- public static DllResourceStore GetStore() => new DllResourceStore("osu.Game.Tests.dll");
+ public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly);
public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}");
- public static Stream GetTestBeatmapStream(bool virtualTrack = false) => new DllResourceStore("osu.Game.Resources.dll").GetStream($"Beatmaps/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz");
+ public static Stream GetTestBeatmapStream(bool virtualTrack = false) => OpenResource($"Archives/241526 Soleily - Renatus{(virtualTrack ? "_virtual" : "")}.osz");
public static string GetTestBeatmapForImport(bool virtualTrack = false)
{
diff --git a/osu.Game.Tests/Resources/test-sample.mp3 b/osu.Game.Tests/Resources/test-sample.mp3
new file mode 100644
index 0000000000..f7c344f39a
Binary files /dev/null and b/osu.Game.Tests/Resources/test-sample.mp3 differ
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/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
index e3688c276f..72fc6d8bd2 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.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;
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/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/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/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index f68f4b8b83..ad5950d9fc 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);
@@ -221,6 +233,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/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/TestSceneSongProgress.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
index af21007efe..9a217ae416 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSongProgress.cs
@@ -5,7 +5,7 @@ using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects;
using osu.Game.Screens.Play;
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
index 68ad0b42b4..1e3e06ce7a 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapPanel.cs
@@ -7,7 +7,7 @@ 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.Framework.Utils;
using osu.Game.Audio;
using osu.Framework.Allocation;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
index 96c0c59695..990e0a166b 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlayDetails.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.Beatmaps;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Screens.Select.Details;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
index 80fad44593..2b572c1f6c 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlaySuccessRate.cs
@@ -8,7 +8,7 @@ using NUnit.Framework;
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.BeatmapSet;
using osu.Game.Screens.Select.Details;
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/TestSceneRankingsCountryFilter.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs
new file mode 100644
index 0000000000..7ac65181f9
--- /dev/null
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsCountryFilter.cs
@@ -0,0 +1,76 @@
+// 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;
+
+namespace osu.Game.Tests.Visual.Online
+{
+ public class TestSceneRankingsCountryFilter : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CountryFilter),
+ typeof(CountryPill)
+ };
+
+ 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/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index b19f2dbf31..1b136d9e41 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
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.BeatmapSet.Scores;
using osu.Game.Rulesets.Osu.Mods;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs b/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs
index 4702d24125..f14c75084f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneTotalCommentsCounter.cs
@@ -6,7 +6,7 @@ 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;
namespace osu.Game.Tests.Visual.Online
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
index 63b8acb234..63b46c991f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileHeader.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(ProfileHeader),
typeof(RankGraph),
typeof(LineGraph),
- typeof(OverlayHeaderTabControl),
+ typeof(TabControlOverlayHeader.OverlayHeaderTabControl),
typeof(CentreHeaderContainer),
typeof(BottomHeaderContainer),
typeof(DetailHeaderContainer),
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 57e297bcd5..3eff75b020 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -3,10 +3,13 @@
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;
using osu.Game.Screens.Select.Leaderboards;
@@ -28,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..eb812f5d5a 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -11,7 +11,7 @@ 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.Game.Beatmaps;
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/TestSceneBreadcrumbs.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs
similarity index 92%
rename from osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbs.cs
rename to osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs
index 554696765e..19eebc89b6 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbs.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBreadcrumbControl.cs
@@ -10,11 +10,11 @@ using osu.Game.Graphics.UserInterface;
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
- public class TestSceneBreadcrumbs : OsuTestScene
+ public class TestSceneBreadcrumbControl : OsuTestScene
{
private readonly BreadcrumbControl breadcrumbs;
- public TestSceneBreadcrumbs()
+ public TestSceneBreadcrumbControl()
{
Add(breadcrumbs = new BreadcrumbControl
{
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/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/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 e3daa9c279..2ea9aec50a 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneNowPlayingOverlay.cs
@@ -4,8 +4,10 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.Timing;
+using osu.Framework.Utils;
+using osu.Game.Beatmaps;
using osu.Game.Overlays;
+using osu.Game.Rulesets.Osu;
namespace osu.Game.Tests.Visual.UserInterface
{
@@ -15,22 +17,48 @@ namespace osu.Game.Tests.Visual.UserInterface
[Cached]
private MusicController musicController = new MusicController();
- public TestSceneNowPlayingOverlay()
- {
- Clock = new FramedClock();
+ private WorkingBeatmap currentBeatmap;
- var np = new NowPlayingOverlay
+ private NowPlayingOverlay nowPlayingOverlay;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
+
+ nowPlayingOverlay = new NowPlayingOverlay
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre
};
Add(musicController);
- Add(np);
+ Add(nowPlayingOverlay);
+ }
- AddStep(@"show", () => np.Show());
+ [Test]
+ public void TestShowHideDisable()
+ {
+ AddStep(@"show", () => nowPlayingOverlay.Show());
AddToggleStep(@"toggle beatmap lock", state => Beatmap.Disabled = state);
- AddStep(@"show", () => np.Hide());
+ AddStep(@"hide", () => nowPlayingOverlay.Hide());
+ }
+
+ [Test]
+ public void TestPrevTrackBehavior()
+ {
+ AddStep(@"Play track", () =>
+ {
+ musicController.NextTrack();
+ currentBeatmap = Beatmap.Value;
+ });
+
+ AddStep(@"Seek track to 6 second", () => musicController.SeekTo(6000));
+ AddUntilStep(@"Wait for current time to update", () => currentBeatmap.Track.CurrentTime > 5000);
+ AddAssert(@"Check action is restart track", () => musicController.PreviousTrack() == PreviousTrackResult.Restart);
+ AddUntilStep("Wait for current time to update", () => Precision.AlmostEquals(currentBeatmap.Track.CurrentTime, 0));
+ AddAssert(@"Check track didn't change", () => currentBeatmap == Beatmap.Value);
+ AddAssert(@"Check action is not restart", () => musicController.PreviousTrack() != PreviousTrackResult.Restart);
}
}
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneScreenBreadcrumbControl.cs
index 0cb8683d72..7386e0fa1f 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 . 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;
@@ -62,7 +61,7 @@ namespace osu.Game.Tests.Visual.UserInterface
waitForCurrent();
pushNext();
waitForCurrent();
- AddAssert(@"only 2 items", () => breadcrumbs.Items.Count() == 2);
+ AddAssert(@"only 2 items", () => breadcrumbs.Items.Count == 2);
AddStep(@"exit current", () => screenStack.CurrentScreen.Exit());
AddAssert(@"current screen is first", () => startScreen == screenStack.CurrentScreen);
}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs
index 0da256855a..9738f73548 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneToolbarRulesetSelector.cs
@@ -9,7 +9,7 @@ using osu.Framework.Graphics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets;
namespace osu.Game.Tests.Visual.UserInterface
@@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.UserInterface
AddStep("Select random", () =>
{
- selector.Current.Value = selector.Items.ElementAt(RNG.Next(selector.Items.Count()));
+ selector.Current.Value = selector.Items.ElementAt(RNG.Next(selector.Items.Count));
});
AddStep("Toggle disabled state", () => selector.Current.Disabled = !selector.Current.Disabled);
}
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs
index 72d9eb0e07..77119f7a60 100644
--- a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs
+++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs
@@ -3,7 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Screens.Gameplay.Components;
diff --git a/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs b/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs
index 1cd942b987..f21f5c9460 100644
--- a/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs
+++ b/osu.Game.Tournament/Screens/Drawings/Components/VisualiserContainer.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
namespace osu.Game.Tournament.Screens.Drawings.Components
{
diff --git a/osu.Game.Tournament/TournamentFont.cs b/osu.Game.Tournament/TournamentFont.cs
index f9e60ff2bc..32f0264562 100644
--- a/osu.Game.Tournament/TournamentFont.cs
+++ b/osu.Game.Tournament/TournamentFont.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Tournament
string weightString = weight.ToString();
// Only exo has an explicit "regular" weight, other fonts do not
- if (weight == FontWeight.Regular && family != GetFamilyString(TournamentTypeface.Aquatico) && family != GetFamilyString(TournamentTypeface.Aquatico))
+ if (weight == FontWeight.Regular && family != GetFamilyString(TournamentTypeface.Aquatico))
weightString = string.Empty;
return weightString;
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index 4d7abfe272..17d7dc0245 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -52,7 +52,7 @@ namespace osu.Game.Tournament
[BackgroundDependencyLoader]
private void load(Storage storage, FrameworkConfigManager frameworkConfig)
{
- Resources.AddStore(new DllResourceStore(@"osu.Game.Tournament.dll"));
+ Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));
AddFont(Resources, @"Resources/Fonts/Aquatico-Regular");
AddFont(Resources, @"Resources/Fonts/Aquatico-Light");
@@ -223,9 +223,12 @@ namespace osu.Game.Tournament
foreach (var r in ladder.Rounds)
{
- foreach (var b in r.Beatmaps)
+ foreach (var b in r.Beatmaps.ToList())
{
- if (b.BeatmapInfo == null && b.ID > 0)
+ if (b.BeatmapInfo != null)
+ continue;
+
+ if (b.ID > 0)
{
var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
API.Perform(req);
@@ -233,6 +236,10 @@ namespace osu.Game.Tournament
addedInfo = true;
}
+
+ if (b.BeatmapInfo == null)
+ // if online population couldn't be performed, ensure we don't leave a null value behind
+ r.Beatmaps.Remove(b);
}
}
diff --git a/osu.Game/Audio/HitSampleInfo.cs b/osu.Game/Audio/HitSampleInfo.cs
index 23a74d3fa6..f6b0107bd2 100644
--- a/osu.Game/Audio/HitSampleInfo.cs
+++ b/osu.Game/Audio/HitSampleInfo.cs
@@ -17,11 +17,6 @@ namespace osu.Game.Audio
public const string HIT_NORMAL = @"hitnormal";
public const string HIT_CLAP = @"hitclap";
- ///
- /// An optional ruleset namespace.
- ///
- public string Namespace;
-
///
/// The bank to load the sample from.
///
@@ -49,15 +44,6 @@ namespace osu.Game.Audio
{
get
{
- if (!string.IsNullOrEmpty(Namespace))
- {
- if (!string.IsNullOrEmpty(Suffix))
- yield return $"{Namespace}/{Bank}-{Name}{Suffix}";
-
- yield return $"{Namespace}/{Bank}-{Name}";
- }
-
- // check non-namespace as a fallback even when we have a namespace
if (!string.IsNullOrEmpty(Suffix))
yield return $"{Bank}-{Name}{Suffix}";
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index a10ad73817..31869f9310 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
@@ -26,6 +27,8 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects;
+using Decoder = osu.Game.Beatmaps.Formats.Decoder;
+using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
namespace osu.Game.Beatmaps
{
@@ -56,14 +59,11 @@ namespace osu.Game.Beatmaps
protected override string ImportFromStablePath => "Songs";
private readonly RulesetStore rulesets;
-
private readonly BeatmapStore beatmaps;
-
private readonly AudioManager audioManager;
-
private readonly GameHost host;
-
private readonly BeatmapUpdateQueue updateQueue;
+ private readonly Storage exportStorage;
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, AudioManager audioManager, GameHost host = null,
WorkingBeatmap defaultBeatmap = null)
@@ -80,6 +80,7 @@ namespace osu.Game.Beatmaps
beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b);
updateQueue = new BeatmapUpdateQueue(api);
+ exportStorage = storage.GetStorageForDirectory("exports");
}
protected override ArchiveDownloadRequest CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
@@ -174,6 +175,50 @@ namespace osu.Game.Beatmaps
/// The beatmap difficulty to restore.
public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap);
+ ///
+ /// Saves an file against a given .
+ ///
+ /// The to save the content against. The file referenced by will be replaced.
+ /// The content to write.
+ public void Save(BeatmapInfo info, IBeatmap beatmapContent)
+ {
+ var setInfo = QueryBeatmapSet(s => s.Beatmaps.Any(b => b.ID == info.ID));
+
+ using (var stream = new MemoryStream())
+ {
+ using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
+ new LegacyBeatmapEncoder(beatmapContent).Encode(sw);
+
+ stream.Seek(0, SeekOrigin.Begin);
+
+ UpdateFile(setInfo, setInfo.Files.Single(f => string.Equals(f.Filename, info.Path, StringComparison.OrdinalIgnoreCase)), stream);
+ }
+
+ var working = workingCache.FirstOrDefault(w => w.BeatmapInfo?.ID == info.ID);
+ if (working != null)
+ workingCache.Remove(working);
+ }
+
+ ///
+ /// Exports a to an .osz package.
+ ///
+ /// The to export.
+ public void Export(BeatmapSetInfo set)
+ {
+ var localSet = QueryBeatmapSet(s => s.ID == set.ID);
+
+ using (var archive = ZipArchive.Create())
+ {
+ foreach (var file in localSet.Files)
+ archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
+
+ using (var outputStream = exportStorage.GetStream($"{set}.osz", FileAccess.Write, FileMode.Create))
+ archive.SaveTo(outputStream);
+
+ exportStorage.OpenInNativeExplorer();
+ }
+ }
+
private readonly WeakList workingCache = new WeakList();
///
diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
index 7bd40af512..a3128e36c4 100644
--- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
+++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs
@@ -48,11 +48,9 @@ namespace osu.Game.Beatmaps.Drawables
InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
}
- public string TooltipText { get; set; }
-
public ITooltip GetCustomTooltip() => new DifficultyIconTooltip();
- public object TooltipContent { get; set; }
+ public object TooltipContent { get; }
[BackgroundDependencyLoader]
private void load(OsuColour colours)
diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
index 433becd8cc..09f40ce7b6 100644
--- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
@@ -63,7 +63,7 @@ namespace osu.Game.Beatmaps.Formats
writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}"));
// Todo: Not all countdown types are supported by lazer yet
writer.WriteLine(FormattableString.Invariant($"Countdown: {(beatmap.BeatmapInfo.Countdown ? '1' : '0')}"));
- writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank(beatmap.ControlPointInfo.SamplePoints[0].SampleBank)}"));
+ writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank(beatmap.ControlPointInfo.SamplePointAt(double.MinValue).SampleBank)}"));
writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}"));
writer.WriteLine(FormattableString.Invariant($"Mode: {beatmap.BeatmapInfo.RulesetID}"));
writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.BeatmapInfo.LetterboxInBreaks ? '1' : '0')}"));
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
index b1b27278fe..c46634e72f 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
@@ -12,6 +12,7 @@ using osu.Framework.Graphics;
using osu.Game.IO;
using osu.Game.Storyboards;
using osu.Game.Beatmaps.Legacy;
+using osu.Framework.Utils;
namespace osu.Game.Beatmaps.Formats
{
@@ -190,7 +191,7 @@ namespace osu.Game.Beatmaps.Formats
{
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
- timelineGroup?.Rotation.Add(easing, startTime, endTime, MathHelper.RadiansToDegrees(startValue), MathHelper.RadiansToDegrees(endValue));
+ timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue));
break;
}
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 6aba5257f5..05c344b199 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -7,13 +7,11 @@ using osu.Game.Rulesets.Mods;
using System;
using System.Collections.Generic;
using osu.Game.Storyboards;
-using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Statistics;
-using osu.Game.IO.Serialization;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.UI;
@@ -76,21 +74,6 @@ namespace osu.Game.Beatmaps
return AudioManager.Tracks.GetVirtual(length);
}
- ///
- /// Saves the .
- ///
- /// The absolute path of the output file.
- public string Save()
- {
- string directory = Path.Combine(Path.GetTempPath(), @"osu!");
- Directory.CreateDirectory(directory);
-
- var path = Path.Combine(directory, Guid.NewGuid().ToString().Replace("-", string.Empty) + ".json");
- using (var sw = new StreamWriter(path))
- sw.WriteLine(Beatmap.Serialize());
- return path;
- }
-
///
/// Creates a to convert a for a specified .
///
diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs
index 45fe034a70..5e237d2ecb 100644
--- a/osu.Game/Database/ArchiveModelManager.cs
+++ b/osu.Game/Database/ArchiveModelManager.cs
@@ -34,7 +34,7 @@ namespace osu.Game.Database
/// The associated file join type.
public abstract class ArchiveModelManager : ICanAcceptFiles, IModelManager
where TModel : class, IHasFiles, IHasPrimaryKey, ISoftDelete
- where TFileModel : INamedFileInfo, new()
+ where TFileModel : class, INamedFileInfo, new()
{
private const int import_queue_request_concurrency = 1;
@@ -222,9 +222,8 @@ namespace osu.Game.Database
{
model = CreateModel(archive);
- if (model == null) return Task.FromResult(null);
-
- model.Hash = computeHash(archive);
+ if (model == null)
+ return Task.FromResult(null);
}
catch (TaskCanceledException)
{
@@ -262,18 +261,24 @@ namespace osu.Game.Database
///
/// In the case of no matching files, a hash will be generated from the passed archive's .
///
- private string computeHash(ArchiveReader reader)
+ private string computeHash(TModel item, ArchiveReader reader = null)
{
// for now, concatenate all .osu files in the set to create a unique hash.
MemoryStream hashable = new MemoryStream();
- foreach (string file in reader.Filenames.Where(f => HashableFileTypes.Any(f.EndsWith)))
+ foreach (TFileModel file in item.Files.Where(f => HashableFileTypes.Any(f.Filename.EndsWith)))
{
- using (Stream s = reader.GetStream(file))
+ using (Stream s = Files.Store.GetStream(file.FileInfo.StoragePath))
s.CopyTo(hashable);
}
- return hashable.Length > 0 ? hashable.ComputeSHA2Hash() : reader.Name.ComputeSHA2Hash();
+ if (hashable.Length > 0)
+ return hashable.ComputeSHA2Hash();
+
+ if (reader != null)
+ return reader.Name.ComputeSHA2Hash();
+
+ return item.Hash;
}
///
@@ -303,6 +308,7 @@ namespace osu.Game.Database
LogForModel(item, "Beginning import...");
item.Files = archive != null ? createFileInfos(archive, Files) : new List();
+ item.Hash = computeHash(item, archive);
await Populate(item, archive, cancellationToken);
@@ -358,12 +364,42 @@ namespace osu.Game.Database
return item;
}, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap();
+ public void UpdateFile(TModel model, TFileModel file, Stream contents)
+ {
+ using (var usage = ContextFactory.GetForWrite())
+ {
+ // Dereference the existing file info, since the file model will be removed.
+ Files.Dereference(file.FileInfo);
+
+ // Remove the file model.
+ usage.Context.Set().Remove(file);
+
+ // Add the new file info and containing file model.
+ model.Files.Remove(file);
+ model.Files.Add(new TFileModel
+ {
+ Filename = file.Filename,
+ FileInfo = Files.Add(contents)
+ });
+
+ Update(model);
+ }
+ }
+
///
/// Perform an update of the specified item.
- /// TODO: Support file changes.
+ /// TODO: Support file additions/removals.
///
/// The item to update.
- public void Update(TModel item) => ModelStore.Update(item);
+ public void Update(TModel item)
+ {
+ using (ContextFactory.GetForWrite())
+ {
+ item.Hash = computeHash(item);
+
+ ModelStore.Update(item);
+ }
+ }
///
/// Delete an item from the manager.
diff --git a/osu.Game/Database/DownloadableArchiveModelManager.cs b/osu.Game/Database/DownloadableArchiveModelManager.cs
index 5f688c149d..4bd9df5f36 100644
--- a/osu.Game/Database/DownloadableArchiveModelManager.cs
+++ b/osu.Game/Database/DownloadableArchiveModelManager.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Database
/// The associated file join type.
public abstract class DownloadableArchiveModelManager : ArchiveModelManager, IModelDownloader
where TModel : class, IHasFiles, IHasPrimaryKey, ISoftDelete, IEquatable
- where TFileModel : INamedFileInfo, new()
+ where TFileModel : class, INamedFileInfo, new()
{
public event Action> DownloadBegan;
@@ -92,8 +92,6 @@ namespace osu.Game.Database
notification.CancelRequested += () =>
{
request.Cancel();
- currentDownloads.Remove(request);
- notification.State = ProgressNotificationState.Cancelled;
return true;
};
@@ -109,11 +107,11 @@ namespace osu.Game.Database
{
DownloadFailed?.Invoke(request);
- if (error is OperationCanceledException) return;
-
- notification.State = ProgressNotificationState.Cancelled;
- Logger.Error(error, $"{HumanisedModelName.Titleize()} download failed!");
currentDownloads.Remove(request);
+ notification.State = ProgressNotificationState.Cancelled;
+
+ if (!(error is OperationCanceledException))
+ Logger.Error(error, $"{HumanisedModelName.Titleize()} download failed!");
}
}
diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs
index 6d88808150..b9c7b26e3e 100644
--- a/osu.Game/Graphics/Backgrounds/Triangles.cs
+++ b/osu.Game/Graphics/Backgrounds/Triangles.cs
@@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osuTK;
using osuTK.Graphics;
using System;
@@ -29,8 +29,33 @@ namespace osu.Game.Graphics.Backgrounds
///
private const float edge_smoothness = 1;
- public Color4 ColourLight = Color4.White;
- public Color4 ColourDark = Color4.Black;
+ private Color4 colourLight = Color4.White;
+
+ public Color4 ColourLight
+ {
+ get => colourLight;
+ set
+ {
+ if (colourLight == value) return;
+
+ colourLight = value;
+ updateColours();
+ }
+ }
+
+ private Color4 colourDark = Color4.Black;
+
+ public Color4 ColourDark
+ {
+ get => colourDark;
+ set
+ {
+ if (colourDark == value) return;
+
+ colourDark = value;
+ updateColours();
+ }
+ }
///
/// Whether we want to expire triangles as they exit our draw area completely.
@@ -151,7 +176,8 @@ namespace osu.Game.Graphics.Backgrounds
TriangleParticle particle = CreateTriangle();
particle.Position = new Vector2(RNG.NextSingle(), randomY ? RNG.NextSingle() : 1);
- particle.Colour = CreateTriangleShade();
+ particle.ColourShade = RNG.NextSingle();
+ particle.Colour = CreateTriangleShade(particle.ColourShade);
return particle;
}
@@ -177,7 +203,17 @@ namespace osu.Game.Graphics.Backgrounds
/// Creates a shade of colour for the triangles.
///
/// The colour.
- protected virtual Color4 CreateTriangleShade() => Interpolation.ValueAt(RNG.NextSingle(), ColourDark, ColourLight, 0, 1);
+ protected virtual Color4 CreateTriangleShade(float shade) => Interpolation.ValueAt(shade, colourDark, colourLight, 0, 1);
+
+ private void updateColours()
+ {
+ for (int i = 0; i < parts.Count; i++)
+ {
+ TriangleParticle newParticle = parts[i];
+ newParticle.Colour = CreateTriangleShade(newParticle.ColourShade);
+ parts[i] = newParticle;
+ }
+ }
protected override DrawNode CreateDrawNode() => new TrianglesDrawNode(this);
@@ -264,6 +300,12 @@ namespace osu.Game.Graphics.Backgrounds
///
public Vector2 Position;
+ ///
+ /// The colour shade of the triangle.
+ /// This is needed for colour recalculation of visible triangles when or is changed.
+ ///
+ public float ColourShade;
+
///
/// The colour of the triangle.
///
diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
index b9ef279f5c..be9aefa359 100644
--- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
+++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
@@ -38,6 +38,11 @@ namespace osu.Game.Graphics.Containers
///
public int Divisor { get; set; } = 1;
+ ///
+ /// An optional minimum beat length. Any beat length below this will be multiplied by two until valid.
+ ///
+ public double MinimumBeatLength { get; set; }
+
///
/// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
///
@@ -89,6 +94,9 @@ namespace osu.Game.Graphics.Containers
double beatLength = timingPoint.BeatLength / Divisor;
+ while (beatLength < MinimumBeatLength)
+ beatLength *= 2;
+
int beatIndex = (int)((currentTrackTime - timingPoint.Time) / beatLength) - (effectPoint.OmitFirstBarLine ? 1 : 0);
// The beats before the start of the first control point are off by 1, this should do the trick
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 9735f6373d..e3a9a5fe9d 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -63,7 +63,7 @@ namespace osu.Game.Graphics.Containers
}
public void AddUserLink(User user, Action creationParameters = null)
- => createLink(AddText(user.Username, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user.Id.ToString()), "View Profile");
+ => createLink(AddText(user.Username, creationParameters), new LinkDetails(LinkAction.OpenUserProfile, user.Id.ToString()), "view profile");
private void createLink(IEnumerable drawables, LinkDetails link, string tooltipText, Action action = null)
{
diff --git a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs
index 23015e8bf5..dadd7d5240 100644
--- a/osu.Game/Graphics/Containers/LogoTrackingContainer.cs
+++ b/osu.Game/Graphics/Containers/LogoTrackingContainer.cs
@@ -4,7 +4,7 @@
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Screens.Menu;
using osuTK;
diff --git a/osu.Game/Graphics/Containers/OsuScrollContainer.cs b/osu.Game/Graphics/Containers/OsuScrollContainer.cs
index ab72276ad0..cfd459da5e 100644
--- a/osu.Game/Graphics/Containers/OsuScrollContainer.cs
+++ b/osu.Game/Graphics/Containers/OsuScrollContainer.cs
@@ -123,8 +123,6 @@ namespace osu.Game.Graphics.Containers
Masking = true;
Child = box = new Box { RelativeSizeAxes = Axes.Both };
-
- ResizeTo(1);
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Graphics/Containers/ParallaxContainer.cs b/osu.Game/Graphics/Containers/ParallaxContainer.cs
index bf743b90ed..4cd3934cde 100644
--- a/osu.Game/Graphics/Containers/ParallaxContainer.cs
+++ b/osu.Game/Graphics/Containers/ParallaxContainer.cs
@@ -9,7 +9,7 @@ using osuTK;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Configuration;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
namespace osu.Game.Graphics.Containers
{
diff --git a/osu.Game/Graphics/Cursor/MenuCursor.cs b/osu.Game/Graphics/Cursor/MenuCursor.cs
index 5a83d8e4ce..170ea63059 100644
--- a/osu.Game/Graphics/Cursor/MenuCursor.cs
+++ b/osu.Game/Graphics/Cursor/MenuCursor.cs
@@ -14,6 +14,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
using osuTK.Input;
+using osu.Framework.Utils;
namespace osu.Game.Graphics.Cursor
{
@@ -55,7 +56,7 @@ namespace osu.Game.Graphics.Cursor
if (dragRotationState == DragRotationState.Rotating && distance > 0)
{
Vector2 offset = e.MousePosition - positionMouseDown;
- float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
+ float degrees = MathUtils.RadiansToDegrees(MathF.Atan2(-offset.X, offset.Y)) + 24.3f;
// Always rotate in the direction of least distance
float diff = (degrees - activeCursor.Rotation) % 360;
diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs
index 2dc12b3e67..6767104576 100644
--- a/osu.Game/Graphics/OsuColour.cs
+++ b/osu.Game/Graphics/OsuColour.cs
@@ -3,6 +3,7 @@
using System;
using osu.Game.Beatmaps;
+using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics
@@ -63,6 +64,46 @@ namespace osu.Game.Graphics
}
}
+ public Color4 ForOverlayElement(OverlayColourScheme colourScheme, float saturation, float lightness, float opacity = 1) => Color4.FromHsl(new Vector4(getBaseHue(colourScheme), saturation, lightness, opacity));
+
+ // See https://github.com/ppy/osu-web/blob/4218c288292d7c810b619075471eaea8bbb8f9d8/app/helpers.php#L1463
+ private static float getBaseHue(OverlayColourScheme colourScheme)
+ {
+ float hue;
+
+ switch (colourScheme)
+ {
+ default:
+ throw new ArgumentException($@"{colourScheme} colour scheme does not provide a hue value in {nameof(getBaseHue)}.");
+
+ case OverlayColourScheme.Red:
+ hue = 0;
+ break;
+
+ case OverlayColourScheme.Pink:
+ hue = 333;
+ break;
+
+ case OverlayColourScheme.Orange:
+ hue = 46;
+ break;
+
+ case OverlayColourScheme.Green:
+ hue = 115;
+ break;
+
+ case OverlayColourScheme.Purple:
+ hue = 255;
+ break;
+
+ case OverlayColourScheme.Blue:
+ hue = 200;
+ break;
+ }
+
+ return hue / 360f;
+ }
+
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = FromHex(@"eeeeff");
public readonly Color4 PurpleLight = FromHex(@"aa88ff");
@@ -165,4 +206,14 @@ namespace osu.Game.Graphics
public readonly Color4 ContextMenuGray = FromHex(@"223034");
}
+
+ public enum OverlayColourScheme
+ {
+ Red,
+ Pink,
+ Orange,
+ Green,
+ Purple,
+ Blue
+ }
}
diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
index 93ea6bbbe6..e2438cc4cd 100644
--- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
+++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs
@@ -15,14 +15,13 @@ namespace osu.Game.Graphics.UserInterface
public class BreadcrumbControl : OsuTabControl
{
private const float padding = 10;
- private const float item_chevron_size = 10;
protected override TabItem CreateTabItem(T value) => new BreadcrumbTabItem(value)
{
AccentColour = AccentColour,
};
- protected override float StripWidth() => base.StripWidth() - (padding + item_chevron_size);
+ protected override float StripWidth => base.StripWidth - TabContainer.FirstOrDefault()?.Padding.Right ?? 0;
public BreadcrumbControl()
{
@@ -41,8 +40,10 @@ namespace osu.Game.Graphics.UserInterface
};
}
- private class BreadcrumbTabItem : OsuTabItem, IStateful
+ protected class BreadcrumbTabItem : OsuTabItem, IStateful
{
+ protected virtual float ChevronSize => 10;
+
public event Action StateChanged;
public readonly SpriteIcon Chevron;
@@ -90,12 +91,12 @@ namespace osu.Game.Graphics.UserInterface
{
Text.Font = Text.Font.With(size: 18);
Text.Margin = new MarginPadding { Vertical = 8 };
- Padding = new MarginPadding { Right = padding + item_chevron_size };
+ Padding = new MarginPadding { Right = padding + ChevronSize };
Add(Chevron = new SpriteIcon
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreLeft,
- Size = new Vector2(item_chevron_size),
+ Size = new Vector2(ChevronSize),
Icon = FontAwesome.Solid.ChevronRight,
Margin = new MarginPadding { Left = padding },
Alpha = 0f,
diff --git a/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs b/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs
index f2f6dd429b..bdc3cd4c49 100644
--- a/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs
+++ b/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs
@@ -7,6 +7,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Extensions.Color4Extensions;
using osuTK;
+using osu.Framework.Input.Events;
namespace osu.Game.Graphics.UserInterface
{
@@ -41,5 +42,17 @@ namespace osu.Game.Graphics.UserInterface
this.FadeOut(transition_duration, Easing.OutQuint);
loading.Hide();
}
+
+ protected override bool Handle(UIEvent e)
+ {
+ switch (e)
+ {
+ // blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer.
+ case ScrollEvent _:
+ return false;
+ }
+
+ return base.Handle(e);
+ }
}
}
diff --git a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs
index 8c00cae08a..7225dbc66f 100644
--- a/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs
+++ b/osu.Game/Graphics/UserInterface/ExternalLinkButton.cs
@@ -57,6 +57,6 @@ namespace osu.Game.Graphics.UserInterface
return true;
}
- public string TooltipText => "View in browser";
+ public string TooltipText => "view in browser";
}
}
diff --git a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
index 418ad038f7..e4a4b1c50e 100644
--- a/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuPasswordTextBox.cs
@@ -104,7 +104,7 @@ namespace osu.Game.Graphics.UserInterface
private class CapsWarning : SpriteIcon, IHasTooltip
{
- public string TooltipText => @"Caps lock is active";
+ public string TooltipText => @"caps lock is active";
public CapsWarning()
{
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
index 064cba6adf..6a7998d5fb 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
@@ -15,7 +15,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
@@ -28,8 +28,7 @@ namespace osu.Game.Graphics.UserInterface
protected override TabItem CreateTabItem(T value) => new OsuTabItem(value);
- protected virtual float StripWidth() => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X;
- protected virtual float StripHeight() => 1;
+ protected virtual float StripWidth => TabContainer.Children.Sum(c => c.IsPresent ? c.DrawWidth + TabContainer.Spacing.X : 0) - TabContainer.Spacing.X;
///
/// Whether entries should be automatically populated if is an type.
@@ -46,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
- Height = StripHeight(),
+ Height = 1,
Colour = Color4.White.Opacity(0),
});
@@ -99,7 +98,7 @@ namespace osu.Game.Graphics.UserInterface
// dont bother calculating if the strip is invisible
if (strip.Colour.MaxAlpha > 0)
- strip.Width = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth(), 0, 500, Easing.OutQuint);
+ strip.Width = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth, 0, 500, Easing.OutQuint);
}
public class OsuTabItem : TabItem, IHasAccentColour
diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs
index 3ee572602b..586cd2ce84 100644
--- a/osu.Game/Graphics/UserInterface/StarCounter.cs
+++ b/osu.Game/Graphics/UserInterface/StarCounter.cs
@@ -4,7 +4,7 @@
using osuTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using System;
using System.Linq;
using osu.Framework.Graphics.Sprites;
diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs
index bf758e21d9..7763577a14 100644
--- a/osu.Game/Input/Bindings/GlobalActionContainer.cs
+++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs
@@ -24,6 +24,7 @@ namespace osu.Game.Input.Bindings
public IEnumerable GlobalKeyBindings => new[]
{
+ new KeyBinding(InputKey.F6, GlobalAction.ToggleNowPlaying),
new KeyBinding(InputKey.F8, GlobalAction.ToggleChat),
new KeyBinding(InputKey.F9, GlobalAction.ToggleSocial),
new KeyBinding(InputKey.F10, GlobalAction.ToggleGameplayMouseButtons),
@@ -32,6 +33,7 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.R }, GlobalAction.ResetInputSettings),
new KeyBinding(new[] { InputKey.Control, InputKey.T }, GlobalAction.ToggleToolbar),
new KeyBinding(new[] { InputKey.Control, InputKey.O }, GlobalAction.ToggleSettings),
+ new KeyBinding(new[] { InputKey.Control, InputKey.D }, GlobalAction.ToggleDirect),
new KeyBinding(InputKey.Escape, GlobalAction.Back),
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
@@ -136,5 +138,8 @@ namespace osu.Game.Input.Bindings
[Description("Play / pause")]
MusicPlay,
+
+ [Description("Toggle now playing overlay")]
+ ToggleNowPlaying,
}
}
diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs
index fcbd4d314a..30c1018c1e 100644
--- a/osu.Game/Online/API/APIRequest.cs
+++ b/osu.Game/Online/API/APIRequest.cs
@@ -14,9 +14,9 @@ namespace osu.Game.Online.API
/// Type of the response (used for deserialisation).
public abstract class APIRequest : APIRequest
{
- protected override WebRequest CreateWebRequest() => new JsonWebRequest(Uri);
+ protected override WebRequest CreateWebRequest() => new OsuJsonWebRequest(Uri);
- public T Result => ((JsonWebRequest)WebRequest).ResponseObject;
+ public T Result => ((OsuJsonWebRequest)WebRequest).ResponseObject;
protected APIRequest()
{
@@ -39,7 +39,7 @@ namespace osu.Game.Online.API
{
protected abstract string Target { get; }
- protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri);
+ protected virtual WebRequest CreateWebRequest() => new OsuWebRequest(Uri);
protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}";
diff --git a/osu.Game/Online/API/OAuth.cs b/osu.Game/Online/API/OAuth.cs
index baf494ebf9..bdc47aab8d 100644
--- a/osu.Game/Online/API/OAuth.cs
+++ b/osu.Game/Online/API/OAuth.cs
@@ -4,7 +4,6 @@
using System.Diagnostics;
using System.Net.Http;
using osu.Framework.Bindables;
-using osu.Framework.IO.Network;
namespace osu.Game.Online.API
{
@@ -166,7 +165,7 @@ namespace osu.Game.Online.API
}
}
- private class AccessTokenRequest : JsonWebRequest
+ private class AccessTokenRequest : OsuJsonWebRequest
{
protected string GrantType;
diff --git a/osu.Game/Online/API/OsuJsonWebRequest.cs b/osu.Game/Online/API/OsuJsonWebRequest.cs
new file mode 100644
index 0000000000..4a45a8b261
--- /dev/null
+++ b/osu.Game/Online/API/OsuJsonWebRequest.cs
@@ -0,0 +1,21 @@
+// 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.IO.Network;
+
+namespace osu.Game.Online.API
+{
+ public class OsuJsonWebRequest : JsonWebRequest
+ {
+ public OsuJsonWebRequest(string uri)
+ : base(uri)
+ {
+ }
+
+ public OsuJsonWebRequest()
+ {
+ }
+
+ protected override string UserAgent => "osu!";
+ }
+}
diff --git a/osu.Game/Online/API/OsuWebRequest.cs b/osu.Game/Online/API/OsuWebRequest.cs
new file mode 100644
index 0000000000..1d27899473
--- /dev/null
+++ b/osu.Game/Online/API/OsuWebRequest.cs
@@ -0,0 +1,21 @@
+// 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.IO.Network;
+
+namespace osu.Game.Online.API
+{
+ public class OsuWebRequest : WebRequest
+ {
+ public OsuWebRequest(string uri)
+ : base(uri)
+ {
+ }
+
+ public OsuWebRequest()
+ {
+ }
+
+ protected override string UserAgent => "osu!";
+ }
+}
diff --git a/osu.Game/Online/API/RegistrationRequest.cs b/osu.Game/Online/API/RegistrationRequest.cs
index 349cd4de0c..f650e5c93b 100644
--- a/osu.Game/Online/API/RegistrationRequest.cs
+++ b/osu.Game/Online/API/RegistrationRequest.cs
@@ -2,11 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using Newtonsoft.Json;
-using osu.Framework.IO.Network;
namespace osu.Game.Online.API
{
- public class RegistrationRequest : WebRequest
+ public class RegistrationRequest : OsuWebRequest
{
internal string Username;
internal string Email;
diff --git a/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs b/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs
new file mode 100644
index 0000000000..95a5d0acbd
--- /dev/null
+++ b/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs
@@ -0,0 +1,30 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Net.Http;
+using osu.Framework.IO.Network;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Online.API.Requests
+{
+ public class MarkChannelAsReadRequest : APIRequest
+ {
+ private readonly Channel channel;
+ private readonly Message message;
+
+ public MarkChannelAsReadRequest(Channel channel, Message message)
+ {
+ this.channel = channel;
+ this.message = message;
+ }
+
+ protected override string Target => $"chat/channels/{channel.Id}/mark-as-read/{message.Id}";
+
+ protected override WebRequest CreateWebRequest()
+ {
+ var req = base.CreateWebRequest();
+ req.Method = HttpMethod.Put;
+ return req;
+ }
+ }
+}
diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs
index 451174a73c..6f67a95f53 100644
--- a/osu.Game/Online/Chat/Channel.cs
+++ b/osu.Game/Online/Chat/Channel.cs
@@ -36,6 +36,11 @@ namespace osu.Game.Online.Chat
///
public readonly SortedList Messages = new SortedList(Comparer.Default);
+ ///
+ /// Contains all the messages that weren't read by the user.
+ ///
+ public IEnumerable UnreadMessages => Messages.Where(m => LastReadId < m.Id);
+
///
/// Contains all the messages that are still pending for submission to the server.
///
@@ -75,6 +80,9 @@ namespace osu.Game.Online.Chat
[JsonProperty(@"last_message_id")]
public long? LastMessageId;
+ [JsonProperty(@"last_read_id")]
+ public long? LastReadId;
+
///
/// Signalles if the current user joined this channel or not. Defaults to false.
///
diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs
index 1d8c5609d9..4b5ec1cad0 100644
--- a/osu.Game/Online/Chat/ChannelManager.cs
+++ b/osu.Game/Online/Chat/ChannelManager.cs
@@ -445,6 +445,28 @@ namespace osu.Game.Online.Chat
return tcs.Task;
}
+ ///
+ /// Marks the as read
+ ///
+ /// The channel that will be marked as read
+ public void MarkChannelAsRead(Channel channel)
+ {
+ if (channel.LastMessageId == channel.LastReadId)
+ return;
+
+ var message = channel.Messages.LastOrDefault();
+
+ if (message == null)
+ return;
+
+ var req = new MarkChannelAsReadRequest(channel, message);
+
+ req.Success += () => channel.LastReadId = message.Id;
+ req.Failure += e => Logger.Error(e, $"Failed to mark channel {channel} up to '{message}' as read");
+
+ api.Queue(req);
+ }
+
[BackgroundDependencyLoader]
private void load(IAPIProvider api)
{
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index 9c48ebd09b..bd4fedabd4 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -12,8 +12,10 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
+using osu.Game.Online.Placeholders;
using osuTK;
using osuTK.Graphics;
@@ -150,7 +152,7 @@ namespace osu.Game.Online.Leaderboards
break;
case PlaceholderState.NotLoggedIn:
- replacePlaceholder(new MessagePlaceholder(@"Please sign in to view online leaderboards!"));
+ replacePlaceholder(new LoginPlaceholder());
break;
case PlaceholderState.NotSupporter:
@@ -180,10 +182,14 @@ namespace osu.Game.Online.Leaderboards
{
new Drawable[]
{
- scrollContainer = new OsuScrollContainer
+ new OsuContextMenuContainer
{
RelativeSizeAxes = Axes.Both,
- ScrollbarVisible = false,
+ Child = scrollContainer = new OsuScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ ScrollbarVisible = false,
+ }
}
},
new Drawable[]
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index 6ac5219282..9c7324d913 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -11,11 +11,15 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays;
using osu.Game.Rulesets.UI;
+using osu.Game.Screens.Select;
using osu.Game.Scoring;
using osu.Game.Users.Drawables;
using osuTK;
@@ -25,7 +29,7 @@ using osu.Game.Online.API;
namespace osu.Game.Online.Leaderboards
{
- public class LeaderboardScore : OsuClickableContainer
+ public class LeaderboardScore : OsuClickableContainer, IHasContextMenu
{
public const float HEIGHT = 60;
@@ -51,6 +55,9 @@ namespace osu.Game.Online.Leaderboards
private List statisticsLabels;
+ [Resolved]
+ private DialogOverlay dialogOverlay { get; set; }
+
public LeaderboardScore(ScoreInfo score, int rank, bool allowHighlight = true)
{
this.score = score;
@@ -359,5 +366,18 @@ namespace osu.Game.Online.Leaderboards
Value = value;
}
}
+
+ public MenuItem[] ContextMenuItems
+ {
+ get
+ {
+ List
public abstract string ShortName { get; }
+ ///
+ /// The playing verb to be shown in the .
+ ///
+ public virtual string PlayingVerb => "Playing solo";
+
///
/// A list of available variant ids.
///
diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
index 0c6b3f67b4..45edc0f4a3 100644
--- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
@@ -3,7 +3,7 @@
using System;
using osu.Framework.Bindables;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Rulesets.Judgements;
namespace osu.Game.Rulesets.Scoring
diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs
index 945dbe4cc9..3edab0745d 100644
--- a/osu.Game/Rulesets/UI/ModIcon.cs
+++ b/osu.Game/Rulesets/UI/ModIcon.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
using osuTK;
using osu.Framework.Bindables;
@@ -20,25 +21,30 @@ namespace osu.Game.Rulesets.UI
public readonly BindableBool Selected = new BindableBool();
private readonly SpriteIcon modIcon;
+ private readonly SpriteText modAcronym;
private readonly SpriteIcon background;
private const float size = 80;
- public IconUsage Icon
- {
- get => modIcon.Icon;
- set => modIcon.Icon = value;
- }
-
private readonly ModType type;
public virtual string TooltipText { get; }
- protected Mod Mod { get; private set; }
+ private Mod mod;
+
+ public Mod Mod
+ {
+ get => mod;
+ set
+ {
+ mod = value;
+ updateMod(value);
+ }
+ }
public ModIcon(Mod mod)
{
- Mod = mod ?? throw new ArgumentNullException(nameof(mod));
+ this.mod = mod ?? throw new ArgumentNullException(nameof(mod));
type = mod.Type;
@@ -56,15 +62,43 @@ namespace osu.Game.Rulesets.UI
Icon = OsuIcon.ModBg,
Shadow = true,
},
+ modAcronym = new OsuSpriteText
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Colour = OsuColour.Gray(84),
+ Alpha = 0,
+ Font = OsuFont.Numeric.With(null, 22f),
+ UseFullGlyphHeight = false,
+ Text = mod.Acronym
+ },
modIcon = new SpriteIcon
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Colour = OsuColour.Gray(84),
- Size = new Vector2(size - 35),
- Icon = mod.Icon
+ Size = new Vector2(45),
+ Icon = FontAwesome.Solid.Question
},
};
+
+ updateMod(mod);
+ }
+
+ private void updateMod(Mod value)
+ {
+ modAcronym.Text = value.Acronym;
+ modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question;
+
+ if (value.Icon is null)
+ {
+ modIcon.FadeOut();
+ modAcronym.FadeIn();
+ return;
+ }
+
+ modIcon.FadeIn();
+ modAcronym.FadeOut();
}
private Color4 backgroundColour;
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
index 1ab3a5b533..3ced9ee753 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBeatmap.cs
@@ -49,9 +49,12 @@ namespace osu.Game.Screens.Backgrounds
Beatmap = beatmap;
InternalChild = dimmable = CreateFadeContainer();
+
dimmable.EnableUserDim.BindTo(EnableUserDim);
dimmable.IsBreakTime.BindTo(IsBreakTime);
dimmable.BlurAmount.BindTo(BlurAmount);
+
+ StoryboardReplacesBackground.BindTo(dimmable.StoryboardReplacesBackground);
}
[BackgroundDependencyLoader]
@@ -99,7 +102,6 @@ namespace osu.Game.Screens.Backgrounds
b.Depth = newDepth;
dimmable.Background = Background = b;
- StoryboardReplacesBackground.BindTo(dimmable.StoryboardReplacesBackground);
}
public override bool Equals(BackgroundScreen other)
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
index 095985e9d1..980a127cf4 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
@@ -4,7 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs
index 54922fec5e..9aa527667b 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs
@@ -6,7 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics.Containers;
using osuTK;
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 14d69cddd1..e212b429b9 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -44,6 +44,9 @@ namespace osu.Game.Screens.Edit
public override bool DisallowExternalBeatmapRulesetChanges => true;
+ [Resolved]
+ private BeatmapManager beatmapManager { get; set; }
+
private Box bottomBackground;
private Container screenContainer;
@@ -56,7 +59,6 @@ namespace osu.Game.Screens.Edit
private EditorBeatmap editorBeatmap;
private DependencyContainer dependencies;
- private GameHost host;
protected override UserActivity InitialActivity => new UserActivity.Editing(Beatmap.Value.BeatmapInfo);
@@ -66,8 +68,6 @@ namespace osu.Game.Screens.Edit
[BackgroundDependencyLoader]
private void load(OsuColour colours, GameHost host)
{
- this.host = host;
-
beatDivisor.Value = Beatmap.Value.BeatmapInfo.BeatDivisor;
beatDivisor.BindValueChanged(divisor => Beatmap.Value.BeatmapInfo.BeatDivisor = divisor.NewValue);
@@ -90,7 +90,8 @@ namespace osu.Game.Screens.Edit
if (RuntimeInfo.IsDesktop)
{
- fileMenuItems.Add(new EditorMenuItem("Export", MenuItemType.Standard, exportBeatmap));
+ fileMenuItems.Add(new EditorMenuItem("Save", MenuItemType.Standard, saveBeatmap));
+ fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap));
fileMenuItems.Add(new EditorMenuItemSpacer());
}
@@ -205,6 +206,15 @@ namespace osu.Game.Screens.Edit
case Key.Right:
seek(e, 1);
return true;
+
+ case Key.S:
+ if (e.ControlPressed)
+ {
+ saveBeatmap();
+ return true;
+ }
+
+ break;
}
return base.OnKeyDown(e);
@@ -292,8 +302,6 @@ namespace osu.Game.Screens.Edit
}
}
- private void exportBeatmap() => host.OpenFileExternally(Beatmap.Value.Save());
-
private void onModeChanged(ValueChangedEvent e)
{
currentScreen?.Exit();
@@ -329,5 +337,13 @@ namespace osu.Game.Screens.Edit
else
clock.SeekForward(!clock.IsRunning, amount);
}
+
+ private void saveBeatmap() => beatmapManager.Save(playableBeatmap.BeatmapInfo, editorBeatmap);
+
+ private void exportBeatmap()
+ {
+ saveBeatmap();
+ beatmapManager.Export(Beatmap.Value.BeatmapSetInfo);
+ }
}
}
diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs
index 93a5f19121..e5e47507f3 100644
--- a/osu.Game/Screens/Edit/EditorClock.cs
+++ b/osu.Game/Screens/Edit/EditorClock.cs
@@ -3,7 +3,7 @@
using System;
using System.Linq;
-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/Screens/Loader.cs b/osu.Game/Screens/Loader.cs
index 41ee01be20..289413c65a 100644
--- a/osu.Game/Screens/Loader.cs
+++ b/osu.Game/Screens/Loader.cs
@@ -6,7 +6,7 @@ using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shaders;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Screens.Menu;
using osuTK;
using osu.Framework.Screens;
diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs
index df83e98494..26455b1dbd 100644
--- a/osu.Game/Screens/Menu/IntroScreen.cs
+++ b/osu.Game/Screens/Menu/IntroScreen.cs
@@ -7,7 +7,7 @@ using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs
index c86f1393a4..50cfe23481 100644
--- a/osu.Game/Screens/Menu/IntroTriangles.cs
+++ b/osu.Game/Screens/Menu/IntroTriangles.cs
@@ -13,7 +13,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Video;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Timing;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index 1a625f8d83..8fc07f5989 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -19,6 +19,7 @@ using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Utils;
namespace osu.Game.Screens.Menu
{
@@ -205,13 +206,13 @@ namespace osu.Game.Screens.Menu
if (audioData[i] < amplitude_dead_zone)
continue;
- float rotation = MathHelper.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
+ float rotation = MathUtils.DegreesToRadians(i / (float)bars_per_visualiser * 360 + j * 360 / visualiser_rounds);
float rotationCos = MathF.Cos(rotation);
float rotationSin = MathF.Sin(rotation);
//taking the cos and sin to the 0..1 range
var barPosition = new Vector2(rotationCos / 2 + 0.5f, rotationSin / 2 + 0.5f) * size;
- var barSize = new Vector2(size * (float)Math.Sqrt(2 * (1 - Math.Cos(MathHelper.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
+ var barSize = new Vector2(size * MathF.Sqrt(2 * (1 - MathF.Cos(MathUtils.DegreesToRadians(360f / bars_per_visualiser)))) / 2f, bar_length * audioData[i]);
//The distance between the position and the sides of the bar.
var bottomOffset = new Vector2(-rotationSin * barSize.X / 2, rotationCos * barSize.X / 2);
//The distance between the bottom side of the bar and the top side.
diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs
index 534400e720..33b6ee8025 100644
--- a/osu.Game/Screens/Menu/OsuLogo.cs
+++ b/osu.Game/Screens/Menu/OsuLogo.cs
@@ -12,7 +12,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
diff --git a/osu.Game/Screens/Play/FailAnimation.cs b/osu.Game/Screens/Play/FailAnimation.cs
index a3caffb620..54c644c999 100644
--- a/osu.Game/Screens/Play/FailAnimation.cs
+++ b/osu.Game/Screens/Play/FailAnimation.cs
@@ -10,7 +10,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
diff --git a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
index 640224c057..7946e6d322 100644
--- a/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
+++ b/osu.Game/Screens/Play/HUD/HoldForMenuButton.cs
@@ -12,7 +12,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs
index 64fcc48004..f37faac988 100644
--- a/osu.Game/Screens/Play/PlayerLoader.cs
+++ b/osu.Game/Screens/Play/PlayerLoader.cs
@@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play
private LogoTrackingContainer content;
- private BeatmapMetadataDisplay info;
+ protected BeatmapMetadataDisplay MetadataInfo;
private bool hideOverlays;
public override bool HideOverlaysOnEnter => hideOverlays;
@@ -96,7 +96,7 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both,
}).WithChildren(new Drawable[]
{
- info = new BeatmapMetadataDisplay(Beatmap.Value, Mods.Value, content.LogoFacade)
+ MetadataInfo = new BeatmapMetadataDisplay(Beatmap.Value, Mods, content.LogoFacade)
{
Alpha = 0,
Anchor = Anchor.Centre,
@@ -138,7 +138,7 @@ namespace osu.Game.Screens.Play
contentIn();
- info.Delay(750).FadeIn(500);
+ MetadataInfo.Delay(750).FadeIn(500);
this.Delay(1800).Schedule(pushWhenLoaded);
if (!muteWarningShownOnce.Value)
@@ -158,7 +158,7 @@ namespace osu.Game.Screens.Play
contentIn();
- info.Loading = true;
+ MetadataInfo.Loading = true;
//we will only be resumed if the player has requested a re-run (see ValidForResume setting above)
loadNewPlayer();
@@ -174,7 +174,7 @@ namespace osu.Game.Screens.Play
player.RestartCount = restartCount;
player.RestartRequested = restartRequested;
- LoadTask = LoadComponentAsync(player, _ => info.Loading = false);
+ LoadTask = LoadComponentAsync(player, _ => MetadataInfo.Loading = false);
}
private void contentIn()
@@ -350,7 +350,7 @@ namespace osu.Game.Screens.Play
}
}
- private class BeatmapMetadataDisplay : Container
+ protected class BeatmapMetadataDisplay : Container
{
private class MetadataLine : Container
{
@@ -379,11 +379,13 @@ namespace osu.Game.Screens.Play
}
private readonly WorkingBeatmap beatmap;
- private readonly IReadOnlyList mods;
+ private readonly Bindable> mods;
private readonly Drawable facade;
private LoadingAnimation loading;
private Sprite backgroundSprite;
+ public IBindable> Mods => mods;
+
public bool Loading
{
set
@@ -401,11 +403,13 @@ namespace osu.Game.Screens.Play
}
}
- public BeatmapMetadataDisplay(WorkingBeatmap beatmap, IReadOnlyList mods, Drawable facade)
+ public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade)
{
this.beatmap = beatmap;
- this.mods = mods;
this.facade = facade;
+
+ this.mods = new Bindable>();
+ this.mods.BindTo(mods);
}
[BackgroundDependencyLoader]
@@ -492,7 +496,7 @@ namespace osu.Game.Screens.Play
Origin = Anchor.TopCentre,
AutoSizeAxes = Axes.Both,
Margin = new MarginPadding { Top = 20 },
- Current = { Value = mods }
+ Current = mods
}
},
}
diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs
index 1a5ed20953..772d326c7f 100644
--- a/osu.Game/Screens/Play/SkipOverlay.cs
+++ b/osu.Game/Screens/Play/SkipOverlay.cs
@@ -19,7 +19,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Containers;
using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Play
diff --git a/osu.Game/Screens/Play/SongProgressBar.cs b/osu.Game/Screens/Play/SongProgressBar.cs
index cdf495e257..9df36c9c2b 100644
--- a/osu.Game/Screens/Play/SongProgressBar.cs
+++ b/osu.Game/Screens/Play/SongProgressBar.cs
@@ -8,7 +8,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Framework.Threading;
namespace osu.Game.Screens.Play
diff --git a/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs b/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs
index 9cc6ea2628..62213720aa 100644
--- a/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs
+++ b/osu.Game/Screens/Ranking/Pages/ReplayDownloadButton.cs
@@ -74,15 +74,15 @@ namespace osu.Game.Screens.Ranking.Pages
switch (replayAvailability)
{
case ReplayAvailability.Local:
- button.TooltipText = @"Watch replay";
+ button.TooltipText = @"watch replay";
break;
case ReplayAvailability.Online:
- button.TooltipText = @"Download replay";
+ button.TooltipText = @"download replay";
break;
default:
- button.TooltipText = @"Replay unavailable";
+ button.TooltipText = @"replay unavailable";
break;
}
}, true);
diff --git a/osu.Game/Screens/Ranking/Pages/RetryButton.cs b/osu.Game/Screens/Ranking/Pages/RetryButton.cs
index 2a281224c1..06d0440b30 100644
--- a/osu.Game/Screens/Ranking/Pages/RetryButton.cs
+++ b/osu.Game/Screens/Ranking/Pages/RetryButton.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Ranking.Pages
},
};
- TooltipText = "Retry";
+ TooltipText = "retry";
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index 4acc619753..4433543ca1 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -9,7 +9,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Game.Configuration;
using osuTK.Input;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@@ -412,6 +412,12 @@ namespace osu.Game.Screens.Select
protected override bool OnKeyDown(KeyDownEvent e)
{
+ // allow for controlling volume when alt is held.
+ // this is required as the VolumeControlReceptor uses OnPressed, which is
+ // executed after all OnKeyDown events.
+ if (e.AltPressed)
+ return base.OnKeyDown(e);
+
int direction = 0;
bool skipDifficulties = false;
diff --git a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs
index c9b6ca7bb3..b32416b361 100644
--- a/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs
+++ b/osu.Game/Screens/Select/BeatmapClearScoresDialog.cs
@@ -14,7 +14,8 @@ namespace osu.Game.Screens.Select
{
public class BeatmapClearScoresDialog : PopupDialog
{
- private ScoreManager scoreManager;
+ [Resolved]
+ private ScoreManager scoreManager { get; set; }
public BeatmapClearScoresDialog(BeatmapInfo beatmap, Action onCompletion)
{
@@ -38,11 +39,5 @@ namespace osu.Game.Screens.Select
},
};
}
-
- [BackgroundDependencyLoader]
- private void load(ScoreManager scoreManager)
- {
- this.scoreManager = scoreManager;
- }
}
}
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index d54c13c7db..451708c1cf 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -13,7 +13,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs
index 6118191302..121491d6ca 100644
--- a/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs
+++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselItem.cs
@@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Graphics;
using osuTK;
using osuTK.Graphics;
diff --git a/osu.Game/Screens/Select/Details/AdvancedStats.cs b/osu.Game/Screens/Select/Details/AdvancedStats.cs
index a147527f6c..b7f60a8370 100644
--- a/osu.Game/Screens/Select/Details/AdvancedStats.cs
+++ b/osu.Game/Screens/Select/Details/AdvancedStats.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
-using System;
using osu.Game.Beatmaps;
using osu.Framework.Bindables;
using System.Collections.Generic;
@@ -118,17 +117,9 @@ namespace osu.Game.Screens.Select.Details
mod.ApplyToDifficulty(adjustedDifficulty);
}
- //mania specific
- if ((Beatmap?.Ruleset?.ID ?? 0) == 3)
- {
- firstValue.Title = "Key Amount";
- firstValue.Value = ((int)MathF.Round(baseDifficulty?.CircleSize ?? 0), (int)MathF.Round(adjustedDifficulty?.CircleSize ?? 0));
- }
- else
- {
- firstValue.Title = "Circle Size";
- firstValue.Value = (baseDifficulty?.CircleSize ?? 0, adjustedDifficulty?.CircleSize);
- }
+ // Account for mania differences
+ firstValue.Title = (Beatmap?.Ruleset?.ID ?? 0) == 3 ? "Key Amount" : "Circle Size";
+ firstValue.Value = (baseDifficulty?.CircleSize ?? 0, adjustedDifficulty?.CircleSize);
starDifficulty.Value = ((float)(Beatmap?.StarDifficulty ?? 0), null);
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 1b45a9d270..e36493c82f 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -103,6 +103,8 @@ namespace osu.Game.Screens.Select.Leaderboards
{
ScoreSelected = s => ScoreSelected?.Invoke(s)
});
+
+ scoreManager.ItemRemoved += onScoreRemoved;
}
protected override void Reset()
@@ -111,6 +113,8 @@ namespace osu.Game.Screens.Select.Leaderboards
TopScore = null;
}
+ private void onScoreRemoved(ScoreInfo score) => Schedule(RefreshScores);
+
protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local;
protected override APIRequest FetchScores(Action> scoresCallback)
@@ -186,5 +190,13 @@ namespace osu.Game.Screens.Select.Leaderboards
{
Action = () => ScoreSelected?.Invoke(model)
};
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (scoreManager != null)
+ scoreManager.ItemRemoved -= onScoreRemoved;
+ }
}
}
diff --git a/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs
new file mode 100644
index 0000000000..97df40fa6d
--- /dev/null
+++ b/osu.Game/Screens/Select/LocalScoreDeleteDialog.cs
@@ -0,0 +1,54 @@
+// 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.Game.Overlays.Dialog;
+using osu.Game.Scoring;
+using System.Diagnostics;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Screens.Select
+{
+ public class LocalScoreDeleteDialog : PopupDialog
+ {
+ private readonly ScoreInfo score;
+
+ [Resolved]
+ private ScoreManager scoreManager { get; set; }
+
+ [Resolved]
+ private BeatmapManager beatmapManager { get; set; }
+
+ public LocalScoreDeleteDialog(ScoreInfo score)
+ {
+ this.score = score;
+ Debug.Assert(score != null);
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ BeatmapInfo beatmap = beatmapManager.QueryBeatmap(b => b.ID == score.BeatmapInfoID);
+ Debug.Assert(beatmap != null);
+
+ string accuracy = string.Format(score.Accuracy == 1 ? "{0:P0}" : "{0:P2}", score.Accuracy);
+ BodyText = $"{score.User} ({accuracy}, {score.Rank})";
+
+ Icon = FontAwesome.Regular.TrashAlt;
+ HeaderText = "Confirm deletion of local score";
+ Buttons = new PopupDialogButton[]
+ {
+ new PopupDialogOkButton
+ {
+ Text = "Yes. Please.",
+ Action = () => scoreManager?.Delete(score)
+ },
+ new PopupDialogCancelButton
+ {
+ Text = "No, I'm still attached.",
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index 48c520986a..671d37fda4 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -175,7 +175,7 @@ namespace osu.Game.Skinning
{
foreach (var lookup in sampleInfo.LookupNames)
{
- var sample = Samples?.Get(getFallbackName(lookup));
+ var sample = Samples?.Get(lookup);
if (sample != null)
return sample;
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
index a076bb54df..ced3b9c1b6 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
@@ -8,7 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Textures;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs
index ac795b3349..c0da0e9c0e 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs
@@ -8,7 +8,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using osu.Framework.MathUtils;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables
diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs
index 18dbd212cc..8926c76018 100644
--- a/osu.Game/Tests/Visual/OsuTestScene.cs
+++ b/osu.Game/Tests/Visual/OsuTestScene.cs
@@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual
}
[Resolved]
- private AudioManager audio { get; set; }
+ protected AudioManager Audio { get; private set; }
protected virtual IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset);
@@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual
CreateWorkingBeatmap(CreateBeatmap(ruleset), null);
protected virtual WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) =>
- new ClockBackedTestWorkingBeatmap(beatmap, storyboard, Clock, audio);
+ new ClockBackedTestWorkingBeatmap(beatmap, storyboard, Clock, Audio);
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
diff --git a/osu.Game/Updater/SimpleUpdateManager.cs b/osu.Game/Updater/SimpleUpdateManager.cs
index f76cba7f41..5412b11b33 100644
--- a/osu.Game/Updater/SimpleUpdateManager.cs
+++ b/osu.Game/Updater/SimpleUpdateManager.cs
@@ -7,8 +7,8 @@ using Newtonsoft.Json;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Sprites;
-using osu.Framework.IO.Network;
using osu.Framework.Platform;
+using osu.Game.Online.API;
using osu.Game.Overlays.Notifications;
namespace osu.Game.Updater
@@ -36,7 +36,7 @@ namespace osu.Game.Updater
{
try
{
- var releases = new JsonWebRequest("https://api.github.com/repos/ppy/osu/releases/latest");
+ var releases = new OsuJsonWebRequest("https://api.github.com/repos/ppy/osu/releases/latest");
await releases.PerformAsync();
diff --git a/osu.Game/Users/Drawables/DrawableAvatar.cs b/osu.Game/Users/Drawables/DrawableAvatar.cs
index ee9af15863..93136e88a0 100644
--- a/osu.Game/Users/Drawables/DrawableAvatar.cs
+++ b/osu.Game/Users/Drawables/DrawableAvatar.cs
@@ -74,7 +74,7 @@ namespace osu.Game.Users.Drawables
private class ClickableArea : OsuClickableContainer
{
- public override string TooltipText => Enabled.Value ? @"View Profile" : null;
+ public override string TooltipText => Enabled.Value ? @"view profile" : null;
protected override bool OnClick(ClickEvent e)
{
diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs
index 8030fc55a2..3c9f201805 100644
--- a/osu.Game/Users/UserActivity.cs
+++ b/osu.Game/Users/UserActivity.cs
@@ -3,6 +3,7 @@
using osu.Game.Beatmaps;
using osu.Game.Graphics;
+using osu.Game.Rulesets;
using osuTK.Graphics;
namespace osu.Game.Users
@@ -44,15 +45,15 @@ namespace osu.Game.Users
{
public BeatmapInfo Beatmap { get; }
- public Rulesets.RulesetInfo Ruleset { get; }
+ public RulesetInfo Ruleset { get; }
- public SoloGame(BeatmapInfo info, Rulesets.RulesetInfo ruleset)
+ public SoloGame(BeatmapInfo info, RulesetInfo ruleset)
{
Beatmap = info;
Ruleset = ruleset;
}
- public override string Status => @"Playing alone";
+ public override string Status => Ruleset.CreateInstance().PlayingVerb;
}
public class Spectating : UserActivity
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 565608b40f..f41c5fee7f 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 60355b8592..bb4a59a601 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -74,7 +74,7 @@
-
+
@@ -82,7 +82,7 @@
-
+
diff --git a/osu.iOS/Info.plist b/osu.iOS/Info.plist
index 5ceccdf99f..249474b1d7 100644
--- a/osu.iOS/Info.plist
+++ b/osu.iOS/Info.plist
@@ -14,8 +14,6 @@
0.1.0
LSRequiresIPhoneOS
- LSSupportsOpeningDocumentsInPlace
-
MinimumOSVersion
10.0
UIDeviceFamily
@@ -23,6 +21,8 @@
1
2
+ UIFileSharingEnabled
+
UILaunchStoryboardName
LaunchScreen
UIRequiredDeviceCapabilities
@@ -51,7 +51,7 @@
UTTypeConformsTo
-
+ public.data
UTTypeIdentifier
sh.ppy.osu.items
@@ -105,6 +105,8 @@
Owner
CFBundleTypeName
Supported osu! files
+ CFBundleTypeRole
+ Viewer
LSItemContentTypes
sh.ppy.osu.items
diff --git a/osu.sln b/osu.sln
index 79823848f0..1d64f6ff10 100644
--- a/osu.sln
+++ b/osu.sln
@@ -65,6 +65,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
osu.TestProject.props = osu.TestProject.props
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "osu.Game.Benchmarks", "osu.Game.Benchmarks\osu.Game.Benchmarks.csproj", "{93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -399,6 +401,18 @@ Global
{5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{5CC222DC-5716-4499-B897-DCBDDA4A5CF9}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Release|Any CPU.Build.0 = Release|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Release|iPhone.Build.0 = Release|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {93632F2D-2BB4-46C1-A7B8-F8CF2FB27118}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE