diff --git a/README.md b/README.md
index a2f6472371..fc9ef51c6b 100644
--- a/README.md
+++ b/README.md
@@ -11,25 +11,70 @@ We are accepting bug reports (please report with as much detail as possible). Fe
# Requirements
- A desktop platform with the [.NET Core SDK 2.2](https://www.microsoft.com/net/learn/get-started) or higher installed.
-- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio Code](https://code.visualstudio.com/) (with the C# plugin installed) or [Jetbrains Rider](https://www.jetbrains.com/rider/) (commercial).
+- When working with the codebase, we recommend using an IDE with intellisense and syntax highlighting, such as [Visual Studio 2017+](https://visualstudio.microsoft.com/vs/), [Jetbrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio Code](https://code.visualstudio.com/).
-# Building and running
+# Running osu!
-If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled (download and run the install executable for your platform).
+## Releases
-Clone the repository including submodules
+If you are not interested in developing the game, please head over to the [releases](https://github.com/ppy/osu/releases) to download a precompiled build with automatic updating enabled.
-`git clone --recurse-submodules https://github.com/ppy/osu`
+- Windows (x64) users should download and run `install.exe`.
+- macOS users (10.12 "Sierra" and higher) should download and run `osu.app.zip`.
+- iOS users can join the [TestFlight beta program](https://t.co/xQJmHkfC18).
-Build and run
+If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
-- Using Visual Studio 2017, Rider or Visual Studio Code (configurations are included)
-- From command line using `dotnet run --project osu.Desktop`. When building for non-development purposes, add `-c Release` to gain higher performance.
-- To run with code analysis, instead use `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
+## Downloading the source code
-Note: If you run from command line under linux, you will need to prefix the output folder to your `LD_LIBRARY_PATH`. See `.vscode/launch.json` for an example
+Clone the repository **including submodules**:
-If you run into issues building you may need to restore nuget packages (commonly via `dotnet restore`). Visual Studio Code users must run `Restore` task from debug tab before attempt to build.
+```shell
+git clone --recurse-submodules https://github.com/ppy/osu
+cd osu
+```
+
+> If you forgot the `--recurse-submodules` option, run this command inside the `osu` directory:
+>
+> `git submodule update --init --recursive`
+
+To update the source code to the latest commit, run the following command inside the `osu` directory:
+
+```shell
+git pull --recurse-submodules
+```
+
+## Building
+
+Build configurations for the recommended IDEs (listed above) are included. You should use the provided Build/Run functionality of your IDE to get things going. When testing or building new components, it's highly encouraged you use the `VisualTests` project/configuration. More information on this provided below.
+
+> Visual Studio Code users must run the `Restore` task before any build attempt.
+
+You can also build and run osu! from the command-line with a single command:
+
+```shell
+dotnet run --project osu.Desktop
+```
+
+If you are not interested in debugging osu!, you can add `-c Release` to gain performance. In this case, you must replace `Debug` with `Release` in any commands mentioned in this document.
+
+If the build fails, try to restore nuget packages with `dotnet restore`.
+
+### A note for Linux users
+
+On Linux, the environment variable `LD_LIBRARY_PATH` must point to the build directory, located at `osu.Desktop/bin/Debug/$NETCORE_VERSION`.
+
+`$NETCORE_VERSION` is the version of .NET Core SDK. You can have it with `grep TargetFramework osu.Desktop/osu.Desktop.csproj | sed -r 's/.*>(.*)<\/.*/\1/'`.
+
+For example, you can run osu! with the following command:
+
+```shell
+LD_LIBRARY_PATH="$(pwd)/osu.Desktop/bin/Debug/netcoreapp2.2" dotnet run --project osu.Desktop
+```
+
+## Code analysis
+
+Code analysis can be run with `powershell ./build.ps1` or `build.sh`. This is currently only supported under windows due to [resharper cli shortcomings](https://youtrack.jetbrains.com/issue/RSRP-410004). Alternative, you can install resharper or use rider to get inline support in your IDE of choice.
# Contributing
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index 2eeb112450..0b50db1f72 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -97,7 +97,7 @@ namespace osu.Desktop
private void fileDrop(object sender, FileDropEventArgs e)
{
- var filePaths = new[] { e.FileName };
+ var filePaths = e.FileNames;
var firstExtension = Path.GetExtension(filePaths.First());
diff --git a/osu.Desktop/Updater/SimpleUpdateManager.cs b/osu.Desktop/Updater/SimpleUpdateManager.cs
index e404ccd2b3..6956eb30b0 100644
--- a/osu.Desktop/Updater/SimpleUpdateManager.cs
+++ b/osu.Desktop/Updater/SimpleUpdateManager.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
-using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
using osu.Framework;
@@ -77,10 +76,10 @@ namespace osu.Desktop.Updater
switch (RuntimeInfo.OS)
{
case RuntimeInfo.Platform.Windows:
- bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".exe"));
+ bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".exe"));
break;
case RuntimeInfo.Platform.MacOsx:
- bestAsset = release.Assets?.FirstOrDefault(f => f.Name.EndsWith(".app.zip"));
+ bestAsset = release.Assets?.Find(f => f.Name.EndsWith(".app.zip"));
break;
}
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index ad08f57c3a..4f0ae3d65d 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -28,8 +28,8 @@
-
-
+
+
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
index 8a90b48180..baa317c759 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseCatchStacker.cs
@@ -26,7 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests
}
};
-
for (int i = 0; i < 512; i++)
beatmap.HitObjects.Add(new Fruit { X = 0.5f + i / 2048f * (i % 10 - 5), StartTime = i * 100, NewCombo = i % 8 == 0 });
diff --git a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs
index 14487b2c7f..3e322d485f 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestCaseHyperDash.cs
@@ -19,7 +19,6 @@ namespace osu.Game.Rulesets.Catch.Tests
{
var beatmap = new Beatmap { BeatmapInfo = { Ruleset = ruleset.RulesetInfo } };
-
for (int i = 0; i < 512; i++)
if (i % 5 < 3)
beatmap.HitObjects.Add(new Fruit { X = i % 10 < 5 ? 0.02f : 0.98f, StartTime = i * 100, NewCombo = i % 8 == 0 });
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index e875af5a30..feab3ed81c 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
index a763989750..b082497e5e 100644
--- a/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Catch/Difficulty/CatchDifficultyCalculator.cs
@@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty
{
public class CatchDifficultyCalculator : DifficultyCalculator
{
-
///
/// In milliseconds. For difficulty calculation we will only look at the highest strain value in each time interval of size STRAIN_STEP.
/// This is to eliminate higher influence of stream over aim by simply having more HitObjects with high strain.
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
index 2db252ebc6..4c65dbc9e1 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
base.SkinChanged(skin, allowFallback);
if (HitObject is IHasComboInformation combo)
- AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
+ AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : Color4.White);
}
private const float preempt = 1000;
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index 0c6fbfa7d3..e26d2433f9 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
index 2770a6ff5b..1a0cfa7fbb 100644
--- a/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
+++ b/osu.Game.Rulesets.Mania/Beatmaps/ManiaBeatmapConverter.cs
@@ -180,7 +180,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
foreach (var obj in newPattern.HitObjects)
yield return obj;
-
}
}
diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
index 7b4d4b12ed..133c96b16e 100644
--- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs
@@ -53,7 +53,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty
if (!calculateStrainValues(difficultyHitObjects, timeRate))
return new DifficultyAttributes(mods, 0);
-
double starRating = calculateDifficulty(difficultyHitObjects, timeRate) * star_scaling_factor;
return new ManiaDifficultyAttributes(mods, starRating)
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
index 68325b40bf..34e65e8b02 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMirror.cs
@@ -3,14 +3,14 @@
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
using System.Linq;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Mania.Beatmaps;
namespace osu.Game.Rulesets.Mania.Mods
{
- public class ManiaModMirror : Mod, IApplicableToRulesetContainer
+ public class ManiaModMirror : Mod, IApplicableToBeatmap
{
public override string Name => "Mirror";
public override string Acronym => "MR";
@@ -18,11 +18,11 @@ namespace osu.Game.Rulesets.Mania.Mods
public override double ScoreMultiplier => 1;
public override bool Ranked => true;
- public void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ public void ApplyToBeatmap(Beatmap beatmap)
{
- var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
+ var availableColumns = ((ManiaBeatmap)beatmap).TotalColumns;
- rulesetContainer.Objects.OfType().ForEach(h => h.Column = availableColumns - 1 - h.Column);
+ beatmap.HitObjects.OfType().ForEach(h => h.Column = availableColumns - 1 - h.Column);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
index b3a3d4280b..4454012d01 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModRandom.cs
@@ -4,15 +4,15 @@
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.MathUtils;
+using osu.Game.Beatmaps;
using osu.Game.Graphics;
+using osu.Game.Rulesets.Mania.Beatmaps;
using osu.Game.Rulesets.Mania.Objects;
-using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.UI;
namespace osu.Game.Rulesets.Mania.Mods
{
- public class ManiaModRandom : Mod, IApplicableToRulesetContainer
+ public class ManiaModRandom : Mod, IApplicableToBeatmap
{
public override string Name => "Random";
public override string Acronym => "RD";
@@ -21,12 +21,12 @@ namespace osu.Game.Rulesets.Mania.Mods
public override string Description => @"Shuffle around the keys!";
public override double ScoreMultiplier => 1;
- public void ApplyToRulesetContainer(RulesetContainer rulesetContainer)
+ public void ApplyToBeatmap(Beatmap beatmap)
{
- var availableColumns = ((ManiaRulesetContainer)rulesetContainer).Beatmap.TotalColumns;
+ var availableColumns = ((ManiaBeatmap)beatmap).TotalColumns;
var shuffledColumns = Enumerable.Range(0, availableColumns).OrderBy(item => RNG.Next()).ToList();
- rulesetContainer.Objects.OfType().ForEach(h => h.Column = shuffledColumns[h.Column]);
+ beatmap.HitObjects.OfType().ForEach(h => h.Column = shuffledColumns[h.Column]);
}
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs
index 390d2b0218..e191a6b1c4 100644
--- a/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs
+++ b/osu.Game.Rulesets.Mania/Objects/ManiaHitObjectDifficulty.cs
@@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Mania.Objects
private readonly int beatmapColumnCount;
-
private readonly double endTime;
private readonly double[] heldUntil;
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 35f137572d..273d29c3de 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/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
index db80948c94..483ff2d409 100644
--- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using osu.Framework.Graphics;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects.Types;
@@ -23,60 +24,70 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
var osuBeatmap = (Beatmap)Beatmap;
- // Reset stacking
- foreach (var h in osuBeatmap.HitObjects)
- h.StackHeight = 0;
+ if (osuBeatmap.HitObjects.Count > 0)
+ {
+ // Reset stacking
+ foreach (var h in osuBeatmap.HitObjects)
+ h.StackHeight = 0;
- if (Beatmap.BeatmapInfo.BeatmapVersion >= 6)
- applyStacking(osuBeatmap);
- else
- applyStackingOld(osuBeatmap);
+ if (Beatmap.BeatmapInfo.BeatmapVersion >= 6)
+ applyStacking(osuBeatmap, 0, osuBeatmap.HitObjects.Count - 1);
+ else
+ applyStackingOld(osuBeatmap);
+ }
}
- private void applyStacking(Beatmap beatmap)
+ private void applyStacking(Beatmap beatmap, int startIndex, int endIndex)
{
- // Extend the end index to include objects they are stacked on
- int extendedEndIndex = beatmap.HitObjects.Count - 1;
- for (int i = beatmap.HitObjects.Count - 1; i >= 0; i--)
+ if (startIndex > endIndex) throw new ArgumentOutOfRangeException(nameof(startIndex), $"{nameof(startIndex)} cannot be greater than {nameof(endIndex)}.");
+ if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), $"{nameof(startIndex)} cannot be less than 0.");
+ if (endIndex < 0) throw new ArgumentOutOfRangeException(nameof(endIndex), $"{nameof(endIndex)} cannot be less than 0.");
+
+ int extendedEndIndex = endIndex;
+ if (endIndex < beatmap.HitObjects.Count - 1)
{
- int stackBaseIndex = i;
- for (int n = stackBaseIndex + 1; n < beatmap.HitObjects.Count; n++)
+ // Extend the end index to include objects they are stacked on
+ for (int i = endIndex; i >= startIndex; i--)
{
- OsuHitObject stackBaseObject = beatmap.HitObjects[stackBaseIndex];
- if (stackBaseObject is Spinner) break;
-
- OsuHitObject objectN = beatmap.HitObjects[n];
- if (objectN is Spinner)
- continue;
-
- double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
- double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
-
- if (objectN.StartTime - endTime > stackThreshold)
- //We are no longer within stacking range of the next object.
- break;
-
- if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance ||
- stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
+ int stackBaseIndex = i;
+ for (int n = stackBaseIndex + 1; n < beatmap.HitObjects.Count; n++)
{
- stackBaseIndex = n;
+ OsuHitObject stackBaseObject = beatmap.HitObjects[stackBaseIndex];
+ if (stackBaseObject is Spinner) break;
- // HitObjects after the specified update range haven't been reset yet
- objectN.StackHeight = 0;
+ OsuHitObject objectN = beatmap.HitObjects[n];
+ if (objectN is Spinner)
+ continue;
+
+ double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
+ double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
+
+ if (objectN.StartTime - endTime > stackThreshold)
+ //We are no longer within stacking range of the next object.
+ break;
+
+ if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance
+ || stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance)
+ {
+ stackBaseIndex = n;
+
+ // HitObjects after the specified update range haven't been reset yet
+ objectN.StackHeight = 0;
+ }
}
- }
- if (stackBaseIndex > extendedEndIndex)
- {
- extendedEndIndex = stackBaseIndex;
- if (extendedEndIndex == beatmap.HitObjects.Count - 1)
- break;
+ if (stackBaseIndex > extendedEndIndex)
+ {
+ extendedEndIndex = stackBaseIndex;
+ if (extendedEndIndex == beatmap.HitObjects.Count - 1)
+ break;
+ }
}
}
//Reverse pass for stack calculation.
- int extendedStartIndex = 0;
- for (int i = extendedEndIndex; i > 0; i--)
+ int extendedStartIndex = startIndex;
+ for (int i = extendedEndIndex; i > startIndex; i--)
{
int n = i;
/* We should check every note which has not yet got a stack.
@@ -155,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
/* We have hit the first slider in a possible stack.
* From this point on, we ALWAYS stack positive regardless.
*/
- while (--n >= 0)
+ while (--n >= startIndex)
{
OsuHitObject objectN = beatmap.HitObjects[n];
if (objectN is Spinner) continue;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
index 8fc2b69267..4f01dbe2f3 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs
@@ -57,6 +57,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
s.Process(h);
}
+ // The peak strain will not be saved for the last section in the above loop
+ foreach (Skill s in skills)
+ s.SaveCurrentPeak();
+
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
double speedRating = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
double starRating = aimRating + speedRating + Math.Abs(aimRating - speedRating) / 2;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
index 16f0af9875..efa23f1a26 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs
@@ -105,13 +105,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
double approachRateFactor = 1.0f;
if (Attributes.ApproachRate > 10.33f)
- approachRateFactor += 0.45f * (Attributes.ApproachRate - 10.33f);
+ approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f);
else if (Attributes.ApproachRate < 8.0f)
{
- // HD is worth more with lower ar!
- if (mods.Any(h => h is OsuModHidden))
- approachRateFactor += 0.02f * (8.0f - Attributes.ApproachRate);
- else
approachRateFactor += 0.01f * (8.0f - Attributes.ApproachRate);
}
@@ -119,7 +115,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
// We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR.
if (mods.Any(h => h is OsuModHidden))
- aimValue *= 1.02 + (11.0f - Attributes.ApproachRate) / 50.0; // Gives a 1.04 bonus for AR10, a 1.06 bonus for AR9, a 1.02 bonus for AR11.
+ aimValue *= 1.0f + 0.04f * (12.0f - Attributes.ApproachRate);
if (mods.Any(h => h is OsuModFlashlight))
{
@@ -152,13 +148,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty
if (beatmapMaxCombo > 0)
speedValue *= Math.Min(Math.Pow(scoreMaxCombo, 0.8f) / Math.Pow(beatmapMaxCombo, 0.8f), 1.0f);
+ double approachRateFactor = 1.0f;
+ if (Attributes.ApproachRate > 10.33f)
+ approachRateFactor += 0.3f * (Attributes.ApproachRate - 10.33f);
+
+ speedValue *= approachRateFactor;
+
if (mods.Any(m => m is OsuModHidden))
- speedValue *= 1.18f;
+ speedValue *= 1.0f + 0.04f * (12.0f - Attributes.ApproachRate);
// Scale the speed value with accuracy _slightly_
- speedValue *= 0.5f + accuracy / 2.0f;
+ speedValue *= 0.02f + accuracy;
// It is important to also consider accuracy difficulty when doing that
- speedValue *= 0.98f + Math.Pow(Attributes.OverallDifficulty, 2) / 2500;
+ speedValue *= 0.96f + Math.Pow(Attributes.OverallDifficulty, 2) / 1600;
return speedValue;
}
@@ -186,7 +188,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
accuracyValue *= Math.Min(1.15f, Math.Pow(amountHitObjectsWithAccuracy / 1000.0f, 0.3f));
if (mods.Any(m => m is OsuModHidden))
- accuracyValue *= 1.02f;
+ accuracyValue *= 1.08f;
if (mods.Any(m => m is OsuModFlashlight))
accuracyValue *= 1.02f;
diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
index a04fb8371f..31b208d7eb 100644
--- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs
@@ -119,8 +119,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing
float approxFollowCircleRadius = (float)(slider.Radius * 3);
var computeVertex = new Action(t =>
{
- double progress = ((int)t - (int)slider.StartTime) / (float)(int)slider.SpanDuration;
- if (progress % 2 > 1)
+ double progress = (t - slider.StartTime) / slider.SpanDuration;
+ if (progress % 2 >= 1)
progress = 1 - progress % 1;
else
progress = progress % 1;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
index 56c4ea639b..8293d56620 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuHitObject.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.SkinChanged(skin, allowFallback);
if (HitObject is IHasComboInformation combo)
- AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : (Color4?)null) ?? Color4.White;
+ AccentColour = skin.GetValue(s => s.ComboColours.Count > 0 ? s.ComboColours[combo.ComboIndex % s.ComboColours.Count] : Color4.White);
}
protected virtual void UpdatePreemptState() => this.FadeIn(HitObject.TimeFadeIn);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
index 8c9252a2da..542b8cc3bc 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableRepeatPoint.cs
@@ -101,7 +101,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
break;
}
-
float aimRotation = MathHelper.RadiansToDegrees((float)Math.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
while (Math.Abs(aimRotation - Rotation) > 180)
aimRotation += aimRotation < Rotation ? 360 : -360;
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index eed9a53ad7..60377e373a 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -14,6 +14,7 @@ using osu.Game.Configuration;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
+using osu.Game.Skinning;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
@@ -151,6 +152,15 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
}
}
+ protected override void SkinChanged(ISkinSource skin, bool allowFallback)
+ {
+ base.SkinChanged(skin, allowFallback);
+
+ Body.AccentColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderTrackOverride") ? s.CustomColours["SliderTrackOverride"] : Body.AccentColour);
+ Body.BorderColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBorder") ? s.CustomColours["SliderBorder"] : Body.BorderColour);
+ Ball.AccentColour = skin.GetValue(s => s.CustomColours.ContainsKey("SliderBall") ? s.CustomColours["SliderBall"] : Ball.AccentColour);
+ }
+
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (userTriggered || Time.Current < slider.EndTime)
diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs
index 2af1de7355..69da1bef6f 100644
--- a/osu.Game.Rulesets.Osu/Objects/Slider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs
@@ -198,7 +198,7 @@ namespace osu.Game.Rulesets.Osu.Objects
if (tickDistance == 0) return;
- var minDistanceFromEnd = Velocity * 0.01;
+ var minDistanceFromEnd = Velocity * 10;
var spanCount = this.SpanCount();
@@ -215,7 +215,7 @@ namespace osu.Game.Rulesets.Osu.Objects
var distanceProgress = d / length;
var timeProgress = reversed ? 1 - distanceProgress : distanceProgress;
- var firstSample = Samples.FirstOrDefault(s => s.Name == SampleInfo.HIT_NORMAL)
+ var firstSample = Samples.Find(s => s.Name == SampleInfo.HIT_NORMAL)
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
var sampleList = new List();
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs
index 4aa30777e9..80beb62d6c 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/GameplayCursor.cs
@@ -39,10 +39,13 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
private int downCount;
- private const float pressed_scale = 1.2f;
- private const float released_scale = 1f;
-
- private float targetScale => downCount > 0 ? pressed_scale : released_scale;
+ private void updateExpandedState()
+ {
+ if (downCount > 0)
+ (ActiveCursor as OsuCursor)?.Expand();
+ else
+ (ActiveCursor as OsuCursor)?.Contract();
+ }
public bool OnPressed(OsuAction action)
{
@@ -51,7 +54,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
case OsuAction.LeftButton:
case OsuAction.RightButton:
downCount++;
- ActiveCursor.ScaleTo(released_scale).ScaleTo(targetScale, 100, Easing.OutQuad);
+ updateExpandedState();
break;
}
@@ -65,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
case OsuAction.LeftButton:
case OsuAction.RightButton:
if (--downCount == 0)
- ActiveCursor.ScaleTo(targetScale, 200, Easing.OutQuad);
+ updateExpandedState();
break;
}
@@ -77,92 +80,106 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
protected override void PopIn()
{
fadeContainer.FadeTo(1, 300, Easing.OutQuint);
- ActiveCursor.ScaleTo(targetScale, 400, Easing.OutQuint);
+ ActiveCursor.ScaleTo(1, 400, Easing.OutQuint);
}
protected override void PopOut()
{
fadeContainer.FadeTo(0.05f, 450, Easing.OutQuint);
- ActiveCursor.ScaleTo(targetScale * 0.8f, 450, Easing.OutQuint);
+ ActiveCursor.ScaleTo(0.8f, 450, Easing.OutQuint);
}
- public class OsuCursor : Container
+ public class OsuCursor : SkinReloadableDrawable
{
- private Drawable cursorContainer;
+ private bool cursorExpand;
private Bindable cursorScale;
private Bindable autoCursorScale;
private readonly IBindable beatmap = new Bindable();
+ private Container expandTarget;
+ private Drawable scaleTarget;
+
public OsuCursor()
{
Origin = Anchor.Centre;
Size = new Vector2(42);
}
+ protected override void SkinChanged(ISkinSource skin, bool allowFallback)
+ {
+ cursorExpand = skin.GetValue(s => s.CursorExpand ?? true);
+ }
+
[BackgroundDependencyLoader]
private void load(OsuConfigManager config, IBindableBeatmap beatmap)
{
- Child = cursorContainer = new SkinnableDrawable("cursor", _ => new CircularContainer
+ InternalChild = expandTarget = new Container
{
RelativeSizeAxes = Axes.Both,
- Masking = true,
- BorderThickness = Size.X / 6,
- BorderColour = Color4.White,
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Shadow,
- Colour = Color4.Pink.Opacity(0.5f),
- Radius = 5,
- },
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0,
- AlwaysPresent = true,
- },
- new CircularContainer
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- BorderThickness = Size.X / 3,
- BorderColour = Color4.White.Opacity(0.5f),
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Alpha = 0,
- AlwaysPresent = true,
- },
- },
- },
- new CircularContainer
- {
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Scale = new Vector2(0.1f),
- Masking = true,
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.White,
- },
- },
- },
- }
- }, restrictSize: false)
- {
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
+ Child = scaleTarget = new SkinnableDrawable("cursor", _ => new CircularContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ BorderThickness = Size.X / 6,
+ BorderColour = Color4.White,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Colour = Color4.Pink.Opacity(0.5f),
+ Radius = 5,
+ },
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ AlwaysPresent = true,
+ },
+ new CircularContainer
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ BorderThickness = Size.X / 3,
+ BorderColour = Color4.White.Opacity(0.5f),
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0,
+ AlwaysPresent = true,
+ },
+ },
+ },
+ new CircularContainer
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Scale = new Vector2(0.1f),
+ Masking = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.White,
+ },
+ },
+ },
+ }
+ }, restrictSize: false)
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ }
};
this.beatmap.BindTo(beatmap);
@@ -187,8 +204,19 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
scale *= (float)(1 - 0.7 * (1 + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY);
}
- cursorContainer.Scale = new Vector2(scale);
+ scaleTarget.Scale = new Vector2(scale);
}
+
+ private const float pressed_scale = 1.2f;
+ private const float released_scale = 1f;
+
+ public void Expand()
+ {
+ if (!cursorExpand) return;
+ expandTarget.ScaleTo(released_scale).ScaleTo(pressed_scale, 100, Easing.OutQuad);
+ }
+
+ public void Contract() => expandTarget.ScaleTo(released_scale, 100, Easing.OutQuad);
}
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index 0fc01deed6..fade054382 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
index 1412bd3cea..153e5733e5 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwell.cs
@@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
if (userTriggered)
{
- var nextTick = ticks.FirstOrDefault(j => !j.IsHit);
+ var nextTick = ticks.Find(j => !j.IsHit);
nextTick?.TriggerResult(HitResult.Great);
diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
index f7e1653cdd..5d45072fd2 100644
--- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs
@@ -149,7 +149,6 @@ namespace osu.Game.Tests.Beatmaps.Formats
using (var stream = Resource.OpenResource(filename))
using (var sr = new StreamReader(stream))
{
-
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(sr);
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms))
diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs
index db66c01814..bfd24f4f34 100644
--- a/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/TestCaseBeatmapCarousel.cs
@@ -40,7 +40,6 @@ namespace osu.Game.Tests.Visual
typeof(DrawableCarouselBeatmapSet),
};
-
private readonly Stack selectedSets = new Stack();
private readonly HashSet eagerSelectedIDs = new HashSet();
@@ -148,7 +147,7 @@ namespace osu.Game.Tests.Visual
private bool selectedBeatmapVisible()
{
- var currentlySelected = carousel.Items.FirstOrDefault(s => s.Item is CarouselBeatmap && s.Item.State == CarouselItemState.Selected);
+ var currentlySelected = carousel.Items.Find(s => s.Item is CarouselBeatmap && s.Item.State == CarouselItemState.Selected);
if (currentlySelected == null)
return true;
return currentlySelected.Item.Visible;
diff --git a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs
index ec85b33919..02d3acb7f4 100644
--- a/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs
+++ b/osu.Game.Tests/Visual/TestCaseBeatmapScoresContainer.cs
@@ -55,7 +55,6 @@ namespace osu.Game.Tests.Visual
AddStep("resize to normal", () => container.ResizeWidthTo(0.8f, 300));
AddStep("online scores", () => scoresContainer.Beatmap = new BeatmapInfo { OnlineBeatmapID = 75, Ruleset = new OsuRuleset().RulesetInfo });
-
scores = new[]
{
new APIScoreInfo
diff --git a/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs b/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs
index 73a97c6269..678acc6130 100644
--- a/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs
+++ b/osu.Game.Tests/Visual/TestCaseBreadcrumbs.cs
@@ -16,7 +16,6 @@ namespace osu.Game.Tests.Visual
public TestCaseBreadcrumbs()
{
-
Add(breadcrumbs = new BreadcrumbControl
{
Anchor = Anchor.Centre,
diff --git a/osu.Game.Tests/Visual/TestCaseChatLink.cs b/osu.Game.Tests/Visual/TestCaseChatLink.cs
index 61c2f47e7d..8aa3283af7 100644
--- a/osu.Game.Tests/Visual/TestCaseChatLink.cs
+++ b/osu.Game.Tests/Visual/TestCaseChatLink.cs
@@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual
linkColour = colours.Blue;
var chatManager = new ChannelManager();
- BindableCollection availableChannels = (BindableCollection)chatManager.AvailableChannels;
+ BindableList availableChannels = (BindableList)chatManager.AvailableChannels;
availableChannels.Add(new Channel { Name = "#english"});
availableChannels.Add(new Channel { Name = "#japanese" });
Dependencies.Cache(chatManager);
diff --git a/osu.Game.Tests/Visual/TestCaseKeyCounter.cs b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs
index 465b943651..bccc27418c 100644
--- a/osu.Game.Tests/Visual/TestCaseKeyCounter.cs
+++ b/osu.Game.Tests/Visual/TestCaseKeyCounter.cs
@@ -39,7 +39,6 @@ namespace osu.Game.Tests.Visual
},
};
-
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
diff --git a/osu.Game.Tests/Visual/TestCaseLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/TestCaseLoungeRoomsContainer.cs
index 3e9f2fb3a4..6b5bc875f1 100644
--- a/osu.Game.Tests/Visual/TestCaseLoungeRoomsContainer.cs
+++ b/osu.Game.Tests/Visual/TestCaseLoungeRoomsContainer.cs
@@ -73,8 +73,8 @@ namespace osu.Game.Tests.Visual
{
public event Action RoomsUpdated;
- public readonly BindableCollection Rooms = new BindableCollection();
- IBindableCollection IRoomManager.Rooms => Rooms;
+ public readonly BindableList Rooms = new BindableList();
+ IBindableList IRoomManager.Rooms => Rooms;
public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => Rooms.Add(room);
diff --git a/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs b/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs
index cf475de1f0..821bf84047 100644
--- a/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs
+++ b/osu.Game.Tests/Visual/TestCaseMatchLeaderboard.cs
@@ -17,12 +17,13 @@ namespace osu.Game.Tests.Visual
{
public TestCaseMatchLeaderboard()
{
- Add(new MatchLeaderboard(new Room { RoomID = { Value = 3 } })
+ Add(new MatchLeaderboard
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Size = new Vector2(550f, 450f),
Scope = MatchLeaderboardScope.Overall,
+ Room = new Room { RoomID = { Value = 3 } }
});
}
diff --git a/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs
index 7fb9d4dded..6f084def48 100644
--- a/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs
+++ b/osu.Game.Tests/Visual/TestCaseMatchSettingsOverlay.cs
@@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual
public event Action RoomsUpdated;
- public IBindableCollection Rooms { get; } = null;
+ public IBindableList Rooms { get; } = null;
public void CreateRoom(Room room, Action onSuccess = null, Action onError = null)
{
diff --git a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs
index 2c56f08f42..66ae2d3012 100644
--- a/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs
+++ b/osu.Game.Tests/Visual/TestCaseNotificationOverlay.cs
@@ -49,7 +49,6 @@ namespace osu.Game.Tests.Visual
manager.UnreadCount.ValueChanged += count => { displayedCount.Text = $"displayed count: {count}"; };
-
setState(Visibility.Visible);
AddStep(@"simple #1", sendHelloNotification);
AddStep(@"simple #2", sendAmazingNotification);
@@ -75,7 +74,6 @@ namespace osu.Game.Tests.Visual
checkProgressingCount(0);
-
setState(Visibility.Visible);
//AddStep(@"barrage", () => sendBarrage());
@@ -111,7 +109,7 @@ namespace osu.Game.Tests.Visual
if (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
{
- var p = progressingNotifications.FirstOrDefault(n => n.State == ProgressNotificationState.Queued);
+ var p = progressingNotifications.Find(n => n.State == ProgressNotificationState.Queued);
if (p != null)
p.State = ProgressNotificationState.Active;
}
diff --git a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs
index 29060ceb12..369d28fc91 100644
--- a/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/TestCasePlaySongSelect.cs
@@ -57,11 +57,19 @@ namespace osu.Game.Tests.Visual
private class TestSongSelect : PlaySongSelect
{
+ public Action StartRequested;
+
public new Bindable Ruleset => base.Ruleset;
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
public new BeatmapCarousel Carousel => base.Carousel;
+
+ protected override bool OnStart()
+ {
+ StartRequested?.Invoke();
+ return base.OnStart();
+ }
}
private TestSongSelect songSelect;
@@ -182,6 +190,27 @@ namespace osu.Game.Tests.Visual
void onRulesetChange(RulesetInfo ruleset) => rulesetChangeIndex = actionIndex--;
}
+ [Test]
+ public void TestStartAfterUnMatchingFilterDoesNotStart()
+ {
+ addManyTestMaps();
+ AddUntilStep(() => songSelect.Carousel.SelectedBeatmap != null, "has selection");
+
+ bool startRequested = false;
+
+ AddStep("set filter and finalize", () =>
+ {
+ songSelect.StartRequested = () => startRequested = true;
+
+ songSelect.Carousel.Filter(new FilterCriteria { SearchText = "somestringthatshouldn'tbematchable" });
+ songSelect.FinaliseSelection();
+
+ songSelect.StartRequested = null;
+ });
+
+ AddAssert("start not requested", () => !startRequested);
+ }
+
private void importForRuleset(int id) => AddStep($"import test map for ruleset {id}", () => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())));
private static int importId;
diff --git a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs
index 6ec3bd108b..2240af39be 100644
--- a/osu.Game.Tests/Visual/TestCasePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/TestCasePlayerLoader.cs
@@ -57,5 +57,4 @@ namespace osu.Game.Tests.Visual
}
}
}
-
}
diff --git a/osu.Game.Tests/Visual/TestCaseSkipButton.cs b/osu.Game.Tests/Visual/TestCaseSkipOverlay.cs
similarity index 89%
rename from osu.Game.Tests/Visual/TestCaseSkipButton.cs
rename to osu.Game.Tests/Visual/TestCaseSkipOverlay.cs
index 4f381fd7a8..62fb78b4ea 100644
--- a/osu.Game.Tests/Visual/TestCaseSkipButton.cs
+++ b/osu.Game.Tests/Visual/TestCaseSkipOverlay.cs
@@ -7,7 +7,7 @@ using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual
{
[TestFixture]
- public class TestCaseSkipButton : OsuTestCase
+ public class TestCaseSkipOverlay : OsuTestCase
{
protected override void LoadComplete()
{
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index e6786dfd15..b22c1aed99 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 0534fd9253..6ad5b2070e 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
+using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
@@ -9,6 +10,7 @@ using Newtonsoft.Json;
using osu.Game.Database;
using osu.Game.IO.Serialization;
using osu.Game.Rulesets;
+using osu.Game.Scoring;
namespace osu.Game.Beatmaps
{
@@ -112,6 +114,11 @@ namespace osu.Game.Beatmaps
[JsonProperty("difficulty_rating")]
public double StarDifficulty { get; set; }
+ ///
+ /// Currently only populated for beatmap deletion. Use to query scores.
+ ///
+ public List Scores { get; set; }
+
public override string ToString() => $"{Metadata} [{Version}]";
public bool Equals(BeatmapInfo other)
diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs
index 8c541e9344..a5399ce8c7 100644
--- a/osu.Game/Beatmaps/BeatmapSetInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Beatmaps
public string Hash { get; set; }
- public string StoryboardFile => Files?.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
+ public string StoryboardFile => Files?.Find(f => f.Filename.EndsWith(".osb"))?.Filename;
public List Files { get; set; }
diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs
index 5bdc42cdf3..6817c0653d 100644
--- a/osu.Game/Beatmaps/BeatmapStore.cs
+++ b/osu.Game/Beatmaps/BeatmapStore.cs
@@ -64,7 +64,8 @@ namespace osu.Game.Beatmaps
base.AddIncludesForDeletion(query)
.Include(s => s.Beatmaps).ThenInclude(b => b.Metadata)
.Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty)
- .Include(s => s.Metadata);
+ .Include(s => s.Metadata)
+ .Include(s => s.Beatmaps).ThenInclude(b => b.Scores);
protected override IQueryable AddIncludesForConsumption(IQueryable query) =>
base.AddIncludesForConsumption(query)
diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs
index 5b76122616..e65409a1d1 100644
--- a/osu.Game/Beatmaps/WorkingBeatmap.cs
+++ b/osu.Game/Beatmaps/WorkingBeatmap.cs
@@ -151,7 +151,7 @@ namespace osu.Game.Beatmaps
public bool WaveformLoaded => waveform.IsResultAvailable;
public Waveform Waveform => waveform.Value;
- protected virtual Waveform GetWaveform() => new Waveform();
+ protected virtual Waveform GetWaveform() => new Waveform(null);
private readonly RecyclableLazy waveform;
public bool StoryboardLoaded => storyboard.IsResultAvailable;
diff --git a/osu.Game/Configuration/DatabasedConfigManager.cs b/osu.Game/Configuration/DatabasedConfigManager.cs
index 0ede6de0f2..334fed2b5a 100644
--- a/osu.Game/Configuration/DatabasedConfigManager.cs
+++ b/osu.Game/Configuration/DatabasedConfigManager.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
-using System.Linq;
using osu.Framework.Configuration;
using osu.Game.Rulesets;
@@ -43,7 +42,7 @@ namespace osu.Game.Configuration
{
base.AddBindable(lookup, bindable);
- var setting = databasedSettings.FirstOrDefault(s => (int)s.Key == (int)(object)lookup);
+ var setting = databasedSettings.Find(s => (int)s.Key == (int)(object)lookup);
if (setting != null)
{
bindable.Parse(setting.Value);
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 8975ab8a0e..1b279eee44 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -3,6 +3,7 @@
using osu.Framework.Configuration;
using osu.Framework.Configuration.Tracking;
+using osu.Framework.Extensions;
using osu.Framework.Platform;
using osu.Game.Overlays;
using osu.Game.Rulesets.Scoring;
@@ -96,15 +97,27 @@ namespace osu.Game.Configuration
Set(OsuSetting.ScreenshotCaptureMenuCursor, false);
Set(OsuSetting.SongSelectRightMouseScroll, false);
+
+ Set(OsuSetting.Scaling, ScalingMode.Off);
+
+ Set(OsuSetting.ScalingSizeX, 0.8f, 0.2f, 1f);
+ Set(OsuSetting.ScalingSizeY, 0.8f, 0.2f, 1f);
+
+ Set(OsuSetting.ScalingPositionX, 0.5f, 0f, 1f);
+ Set(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
+
+ Set(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f);
}
- public OsuConfigManager(Storage storage) : base(storage)
+ public OsuConfigManager(Storage storage)
+ : base(storage)
{
}
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
{
- new TrackedSetting(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled"))
+ new TrackedSetting(OsuSetting.MouseDisableButtons, v => new SettingDescription(!v, "gameplay mouse buttons", v ? "disabled" : "enabled")),
+ new TrackedSetting(OsuSetting.Scaling, m => new SettingDescription(m, "scaling", m.GetDescription())),
};
}
@@ -151,6 +164,12 @@ namespace osu.Game.Configuration
BeatmapHitsounds,
IncreaseFirstObjectVisibility,
ScoreDisplayMode,
- ExternalLinkWarning
+ ExternalLinkWarning,
+ Scaling,
+ ScalingPositionX,
+ ScalingPositionY,
+ ScalingSizeX,
+ ScalingSizeY,
+ UIScale
}
}
diff --git a/osu.Game/Configuration/ScalingMode.cs b/osu.Game/Configuration/ScalingMode.cs
new file mode 100644
index 0000000000..b907d55d82
--- /dev/null
+++ b/osu.Game/Configuration/ScalingMode.cs
@@ -0,0 +1,16 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.ComponentModel;
+
+namespace osu.Game.Configuration
+{
+ public enum ScalingMode
+ {
+ Off,
+ Everything,
+ [Description("Excluding overlays")]
+ ExcludeOverlays,
+ Gameplay,
+ }
+}
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 74315d2522..e4c18dfb3d 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -79,6 +79,7 @@ namespace osu.Game.Graphics.Containers
{
AddInternal(new DrawableLinkCompiler(drawables.OfType().ToList())
{
+ RelativeSizeAxes = Axes.Both,
TooltipText = tooltipText ?? (url != text ? url : string.Empty),
Action = action ?? (() =>
{
@@ -122,5 +123,10 @@ namespace osu.Game.Graphics.Containers
}),
});
}
+
+ // We want the compilers to always be visible no matter where they are, so RelativeSizeAxes is used.
+ // However due to https://github.com/ppy/osu-framework/issues/2073, it's possible for the compilers to be relative size in the flow's auto-size axes - an unsupported operation.
+ // Since the compilers don't display any content and don't affect the layout, it's simplest to exclude them from the flow.
+ public override IEnumerable FlowingChildren => base.FlowingChildren.Where(c => !(c is DrawableLinkCompiler));
}
}
diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs
new file mode 100644
index 0000000000..62760b39ea
--- /dev/null
+++ b/osu.Game/Graphics/Containers/ScalingContainer.cs
@@ -0,0 +1,161 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Configuration;
+using osu.Game.Graphics.Backgrounds;
+using osuTK;
+
+namespace osu.Game.Graphics.Containers
+{
+ ///
+ /// Handles user-defined scaling, allowing application at multiple levels defined by .
+ ///
+ public class ScalingContainer : Container
+ {
+ private Bindable sizeX;
+ private Bindable sizeY;
+ private Bindable posX;
+ private Bindable posY;
+
+ private readonly ScalingMode? targetMode;
+
+ private Bindable scalingMode;
+
+ private readonly Container content;
+ protected override Container Content => content;
+
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
+
+ private readonly Container sizableContainer;
+
+ private Drawable backgroundLayer;
+
+ ///
+ /// Create a new instance.
+ ///
+ /// The mode which this container should be handling. Handles all modes if null.
+ public ScalingContainer(ScalingMode? targetMode = null)
+ {
+ this.targetMode = targetMode;
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChild = sizableContainer = new AlwaysInputContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ RelativePositionAxes = Axes.Both,
+ CornerRadius = 10,
+ Child = content = new ScalingDrawSizePreservingFillContainer(targetMode != ScalingMode.Gameplay)
+ };
+ }
+
+ private class ScalingDrawSizePreservingFillContainer : DrawSizePreservingFillContainer
+ {
+ private readonly bool applyUIScale;
+ private Bindable uiScale;
+
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
+
+ public ScalingDrawSizePreservingFillContainer(bool applyUIScale)
+ {
+ this.applyUIScale = applyUIScale;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuConfigManager osuConfig)
+ {
+ if (applyUIScale)
+ {
+ uiScale = osuConfig.GetBindable(OsuSetting.UIScale);
+ uiScale.BindValueChanged(scaleChanged, true);
+ }
+ }
+
+ private void scaleChanged(float value)
+ {
+ this.ScaleTo(new Vector2(value), 500, Easing.Out);
+ this.ResizeTo(new Vector2(1 / value), 500, Easing.Out);
+ }
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuConfigManager config)
+ {
+ scalingMode = config.GetBindable(OsuSetting.Scaling);
+ scalingMode.ValueChanged += _ => updateSize();
+
+ sizeX = config.GetBindable(OsuSetting.ScalingSizeX);
+ sizeX.ValueChanged += _ => updateSize();
+
+ sizeY = config.GetBindable(OsuSetting.ScalingSizeY);
+ sizeY.ValueChanged += _ => updateSize();
+
+ posX = config.GetBindable(OsuSetting.ScalingPositionX);
+ posX.ValueChanged += _ => updateSize();
+
+ posY = config.GetBindable(OsuSetting.ScalingPositionY);
+ posY.ValueChanged += _ => updateSize();
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ updateSize();
+ sizableContainer.FinishTransforms();
+ }
+
+ private bool requiresBackgroundVisible => (scalingMode == ScalingMode.Everything || scalingMode == ScalingMode.ExcludeOverlays) && (sizeX.Value != 1 || sizeY.Value != 1);
+
+ private void updateSize()
+ {
+ if (targetMode == ScalingMode.Everything)
+ {
+ // the top level scaling container manages the background to be displayed while scaling.
+ if (requiresBackgroundVisible)
+ {
+ if (backgroundLayer == null)
+ LoadComponentAsync(backgroundLayer = new Background("Menu/menu-background-1")
+ {
+ Colour = OsuColour.Gray(0.1f),
+ Alpha = 0,
+ Depth = float.MaxValue
+ }, d =>
+ {
+ AddInternal(d);
+ d.FadeTo(requiresBackgroundVisible ? 1 : 0, 4000, Easing.OutQuint);
+ });
+ else
+ backgroundLayer.FadeIn(500);
+ }
+ else
+ backgroundLayer?.FadeOut(500);
+ }
+
+ bool scaling = targetMode == null || scalingMode.Value == targetMode;
+
+ var targetSize = scaling ? new Vector2(sizeX, sizeY) : Vector2.One;
+ var targetPosition = scaling ? new Vector2(posX, posY) * (Vector2.One - targetSize) : Vector2.Zero;
+ bool requiresMasking = scaling && targetSize != Vector2.One;
+
+ if (requiresMasking)
+ sizableContainer.Masking = true;
+
+ sizableContainer.MoveTo(targetPosition, 500, Easing.OutQuart);
+ sizableContainer.ResizeTo(targetSize, 500, Easing.OutQuart).OnComplete(_ => { sizableContainer.Masking = requiresMasking; });
+ }
+
+ private class AlwaysInputContainer : Container
+ {
+ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
+
+ public AlwaysInputContainer()
+ {
+ RelativeSizeAxes = Axes.Both;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index a59abcbcee..e0f38a13d0 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -8,7 +8,6 @@ using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
-using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Graphics.Cursor;
@@ -33,38 +32,7 @@ namespace osu.Game.Graphics.UserInterface
private readonly Box leftBox;
private readonly Box rightBox;
- public virtual string TooltipText
- {
- get
- {
- var bindableDouble = CurrentNumber as BindableNumber;
- var bindableFloat = CurrentNumber as BindableNumber;
- var floatValue = bindableDouble?.Value ?? bindableFloat?.Value;
- var floatPrecision = bindableDouble?.Precision ?? bindableFloat?.Precision;
-
- if (floatValue != null)
- {
- var floatMinValue = bindableDouble?.MinValue ?? bindableFloat.MinValue;
- var floatMaxValue = bindableDouble?.MaxValue ?? bindableFloat.MaxValue;
-
- if (floatMaxValue == 1 && (floatMinValue == 0 || floatMinValue == -1))
- return floatValue.Value.ToString("P0");
-
- var decimalPrecision = normalise((decimal)floatPrecision, max_decimal_digits);
-
- // Find the number of significant digits (we could have less than 5 after normalize())
- var significantDigits = findPrecision(decimalPrecision);
-
- return floatValue.Value.ToString($"N{significantDigits}");
- }
-
- var bindableInt = CurrentNumber as BindableNumber;
- if (bindableInt != null)
- return bindableInt.Value.ToString("N0");
-
- return Current.Value.ToString(CultureInfo.InvariantCulture);
- }
- }
+ public virtual string TooltipText { get; private set; }
private Color4 accentColour;
public Color4 AccentColour
@@ -124,6 +92,12 @@ namespace osu.Game.Graphics.UserInterface
AccentColour = colours.Pink;
}
+ protected override void LoadComplete()
+ {
+ updateTooltipText(Current.Value);
+ base.LoadComplete();
+ }
+
protected override bool OnHover(HoverEvent e)
{
Nub.Glowing = true;
@@ -136,21 +110,34 @@ namespace osu.Game.Graphics.UserInterface
base.OnHoverLost(e);
}
- protected override void OnUserChange()
+ protected override bool OnMouseDown(MouseDownEvent e)
{
- base.OnUserChange();
- playSample();
+ Nub.Current.Value = true;
+ return base.OnMouseDown(e);
}
- private void playSample()
+ protected override bool OnMouseUp(MouseUpEvent e)
+ {
+ Nub.Current.Value = false;
+ return base.OnMouseUp(e);
+ }
+
+ protected override void OnUserChange(T value)
+ {
+ base.OnUserChange(value);
+ playSample(value);
+ updateTooltipText(value);
+ }
+
+ private void playSample(T value)
{
if (Clock == null || Clock.CurrentTime - lastSampleTime <= 50)
return;
- if (Current.Value.Equals(lastSampleValue))
+ if (value.Equals(lastSampleValue))
return;
- lastSampleValue = Current.Value;
+ lastSampleValue = value;
lastSampleTime = Clock.CurrentTime;
sample.Frequency.Value = 1 + NormalizedValue * 0.2f;
@@ -163,16 +150,28 @@ namespace osu.Game.Graphics.UserInterface
sample.Play();
}
- protected override bool OnMouseDown(MouseDownEvent e)
+ private void updateTooltipText(T value)
{
- Nub.Current.Value = true;
- return base.OnMouseDown(e);
- }
+ if (CurrentNumber.IsInteger)
+ TooltipText = ((int)Convert.ChangeType(value, typeof(int))).ToString("N0");
+ else
+ {
+ double floatValue = (double)Convert.ChangeType(value, typeof(double));
+ double floatMinValue = (double)Convert.ChangeType(CurrentNumber.MinValue, typeof(double));
+ double floatMaxValue = (double)Convert.ChangeType(CurrentNumber.MaxValue, typeof(double));
- protected override bool OnMouseUp(MouseUpEvent e)
- {
- Nub.Current.Value = false;
- return base.OnMouseUp(e);
+ if (floatMaxValue == 1 && floatMinValue >= -1)
+ TooltipText = floatValue.ToString("P0");
+ else
+ {
+ var decimalPrecision = normalise((decimal)Convert.ChangeType(CurrentNumber.Precision, typeof(decimal)), max_decimal_digits);
+
+ // Find the number of significant digits (we could have less than 5 after normalize())
+ var significantDigits = findPrecision(decimalPrecision);
+
+ TooltipText = floatValue.ToString($"N{significantDigits}");
+ }
+ }
}
protected override void UpdateAfterChildren()
diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
index 488e16b6fb..989528e5cd 100644
--- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs
@@ -160,7 +160,6 @@ namespace osu.Game.Graphics.UserInterface
Anchor = Anchor.BottomLeft,
Text = (value as IHasDescription)?.Description ?? (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
- Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
Bar = new Box
{
@@ -173,6 +172,8 @@ namespace osu.Game.Graphics.UserInterface
},
new HoverClickSounds()
};
+
+ Active.BindValueChanged(val => Text.Font = val ? @"Exo2.0-Bold" : @"Exo2.0", true);
}
protected override void OnActivated() => fadeActive();
diff --git a/osu.Game/Graphics/UserInterface/PageTabControl.cs b/osu.Game/Graphics/UserInterface/PageTabControl.cs
index 50e4743028..15a27b1f6f 100644
--- a/osu.Game/Graphics/UserInterface/PageTabControl.cs
+++ b/osu.Game/Graphics/UserInterface/PageTabControl.cs
@@ -46,7 +46,6 @@ namespace osu.Game.Graphics.UserInterface
Anchor = Anchor.BottomLeft,
Text = (value as Enum)?.GetDescription() ?? value.ToString(),
TextSize = 14,
- Font = @"Exo2.0-Bold",
},
box = new Box
{
@@ -59,6 +58,8 @@ namespace osu.Game.Graphics.UserInterface
},
new HoverClickSounds()
};
+
+ Active.BindValueChanged(val => Text.Font = val ? @"Exo2.0-Bold" : @"Exo2.0", true);
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs
index ee64c7c25c..6dca58f70d 100644
--- a/osu.Game/Graphics/UserInterface/ProgressBar.cs
+++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs
@@ -62,6 +62,6 @@ namespace osu.Game.Graphics.UserInterface
fill.Width = value * UsableWidth;
}
- protected override void OnUserChange() => OnSeek?.Invoke(Current);
+ protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
}
}
diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
index 8026847e3b..2dafedc3ac 100644
--- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
+++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
@@ -14,7 +14,7 @@ namespace osu.Game.Migrations
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "2.1.4-rtm-31024");
+ .HasAnnotation("ProductVersion", "2.2.0-rtm-35687");
modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
{
@@ -215,6 +215,25 @@ namespace osu.Game.Migrations
b.ToTable("Settings");
});
+ modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Hash");
+
+ b.Property("ReferenceCount");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("ReferenceCount");
+
+ b.ToTable("FileInfo");
+ });
+
modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b =>
{
b.Property("ID")
@@ -239,25 +258,6 @@ namespace osu.Game.Migrations
b.ToTable("KeyBinding");
});
- modelBuilder.Entity("osu.Game.IO.FileInfo", b =>
- {
- b.Property("ID")
- .ValueGeneratedOnAdd();
-
- b.Property("Hash");
-
- b.Property("ReferenceCount");
-
- b.HasKey("ID");
-
- b.HasIndex("Hash")
- .IsUnique();
-
- b.HasIndex("ReferenceCount");
-
- b.ToTable("FileInfo");
- });
-
modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
{
b.Property("ID")
@@ -454,7 +454,7 @@ namespace osu.Game.Migrations
modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
{
b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
- .WithMany()
+ .WithMany("Scores")
.HasForeignKey("BeatmapInfoID")
.OnDelete(DeleteBehavior.Cascade);
diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs
index 10b4e73419..db273dd00a 100644
--- a/osu.Game/Online/API/APIAccess.cs
+++ b/osu.Game/Online/API/APIAccess.cs
@@ -101,6 +101,9 @@ namespace osu.Game.Online.API
//todo: replace this with a ping request.
log.Add(@"In a failing state, waiting a bit before we try again...");
Thread.Sleep(5000);
+
+ if (!IsLoggedIn) goto case APIState.Connecting;
+
if (queue.Count == 0)
{
log.Add(@"Queueing a ping request");
diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs
index 9dc357c403..982009ed88 100644
--- a/osu.Game/Online/Chat/Channel.cs
+++ b/osu.Game/Online/Chat/Channel.cs
@@ -41,7 +41,6 @@ namespace osu.Game.Online.Chat
///
private readonly List pendingMessages = new List();
-
///
/// An event that fires when new messages arrived.
///
diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs
index 4241b47cd3..d5deda960c 100644
--- a/osu.Game/Online/Chat/ChannelManager.cs
+++ b/osu.Game/Online/Chat/ChannelManager.cs
@@ -29,8 +29,8 @@ namespace osu.Game.Online.Chat
@"#lobby"
};
- private readonly BindableCollection availableChannels = new BindableCollection();
- private readonly BindableCollection joinedChannels = new BindableCollection();
+ private readonly BindableList availableChannels = new BindableList();
+ private readonly BindableList joinedChannels = new BindableList();
///
/// The currently opened channel
@@ -40,12 +40,12 @@ namespace osu.Game.Online.Chat
///
/// The Channels the player has joined
///
- public IBindableCollection JoinedChannels => joinedChannels;
+ public IBindableList JoinedChannels => joinedChannels;
///
/// The channels available for the player to join
///
- public IBindableCollection AvailableChannels => availableChannels;
+ public IBindableList AvailableChannels => availableChannels;
private IAPIProvider api;
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index f3bf16a05f..a6748fa983 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -30,6 +31,7 @@ namespace osu.Game.Online.Leaderboards
private readonly LoadingAnimation loading;
private ScheduledDelegate showScoresDelegate;
+ private CancellationTokenSource showScoresCancellationSource;
private bool scoresLoadedOnce;
@@ -49,6 +51,10 @@ namespace osu.Game.Online.Leaderboards
loading.Hide();
+ // schedule because we may not be loaded yet (LoadComponentAsync complains).
+ showScoresDelegate?.Cancel();
+ showScoresCancellationSource?.Cancel();
+
if (scores == null || !scores.Any())
return;
@@ -58,8 +64,6 @@ namespace osu.Game.Online.Leaderboards
scrollFlow = CreateScoreFlow();
scrollFlow.ChildrenEnumerable = scores.Select((s, index) => CreateDrawableScore(s, index + 1));
- // schedule because we may not be loaded yet (LoadComponentAsync complains).
- showScoresDelegate?.Cancel();
if (!IsLoaded)
showScoresDelegate = Schedule(showScores);
else
@@ -77,7 +81,7 @@ namespace osu.Game.Online.Leaderboards
}
scrollContainer.ScrollTo(0f, false);
- });
+ }, (showScoresCancellationSource = new CancellationTokenSource()).Token);
}
}
diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Multiplayer/PlaylistItem.cs
index 4155121bdf..63b5b95b9c 100644
--- a/osu.Game/Online/Multiplayer/PlaylistItem.cs
+++ b/osu.Game/Online/Multiplayer/PlaylistItem.cs
@@ -37,10 +37,10 @@ namespace osu.Game.Online.Multiplayer
public RulesetInfo Ruleset { get; set; }
[JsonIgnore]
- public readonly BindableCollection AllowedMods = new BindableCollection();
+ public readonly BindableList AllowedMods = new BindableList();
[JsonIgnore]
- public readonly BindableCollection RequiredMods = new BindableCollection();
+ public readonly BindableList RequiredMods = new BindableList();
[JsonProperty("beatmap")]
private APIBeatmap apiBeatmap { get; set; }
diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs
index 448f5ced91..5273c7acfb 100644
--- a/osu.Game/Online/Multiplayer/Room.cs
+++ b/osu.Game/Online/Multiplayer/Room.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Online.Multiplayer
public Bindable Host { get; private set; } = new Bindable();
[JsonProperty("playlist")]
- public BindableCollection Playlist { get; set; } = new BindableCollection();
+ public BindableList Playlist { get; set; } = new BindableList();
[JsonProperty("channel_id")]
public Bindable ChannelId { get; private set; } = new Bindable();
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 2a4c812401..58af93a88b 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -26,6 +26,7 @@ using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Input;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
@@ -187,6 +188,7 @@ namespace osu.Game
}
private ExternalLinkOpener externalLinkOpener;
+
public void OpenUrlExternally(string url)
{
if (url.StartsWith("/"))
@@ -222,7 +224,7 @@ namespace osu.Game
var databasedSet = BeatmapManager.QueryBeatmapSet(s => s.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID);
// Use first beatmap available for current ruleset, else switch ruleset.
- var first = databasedSet.Beatmaps.FirstOrDefault(b => b.Ruleset == ruleset.Value) ?? databasedSet.Beatmaps.First();
+ var first = databasedSet.Beatmaps.Find(b => b.Ruleset == ruleset.Value) ?? databasedSet.Beatmaps.First();
ruleset.Value = first.Ruleset;
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
@@ -353,7 +355,14 @@ namespace osu.Game
ActionRequested = action => volume.Adjust(action),
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
},
- mainContent = new Container { RelativeSizeAxes = Axes.Both },
+ screenContainer = new ScalingContainer(ScalingMode.ExcludeOverlays)
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ mainContent = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
overlayContent = new Container { RelativeSizeAxes = Axes.Both, Depth = float.MinValue },
idleTracker = new IdleTracker(6000)
});
@@ -362,7 +371,7 @@ namespace osu.Game
{
screenStack.ModePushed += screenAdded;
screenStack.Exited += screenRemoved;
- mainContent.Add(screenStack);
+ screenContainer.Add(screenStack);
});
loadComponentSingleFile(Toolbar = new Toolbar
@@ -497,7 +506,7 @@ namespace osu.Game
if (notifications.State == Visibility.Visible)
offset -= ToolbarButton.WIDTH / 2;
- screenStack.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
+ screenContainer.MoveToX(offset, SettingsOverlay.TRANSITION_LENGTH, Easing.OutQuint);
}
settings.StateChanged += _ => updateScreenOffset();
@@ -555,7 +564,7 @@ namespace osu.Game
focused.StateChanged += s =>
{
visibleOverlayCount += s == Visibility.Visible ? 1 : -1;
- screenStack.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
+ screenContainer.FadeColour(visibleOverlayCount > 0 ? OsuColour.Gray(0.5f) : Color4.White, 500, Easing.OutQuint);
};
}
@@ -646,6 +655,7 @@ namespace osu.Game
private OsuScreen currentScreen;
private FrameworkConfigManager frameworkConfig;
+ private ScalingContainer screenContainer;
protected override bool OnExiting()
{
@@ -685,7 +695,7 @@ namespace osu.Game
ruleset.Disabled = applyBeatmapRulesetRestrictions;
Beatmap.Disabled = applyBeatmapRulesetRestrictions;
- mainContent.Padding = new MarginPadding { Top = ToolbarOffset };
+ screenContainer.Padding = new MarginPadding { Top = ToolbarOffset };
MenuCursorContainer.CanShowCursor = currentScreen?.CursorVisible ?? false;
}
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 683fa30818..b6c642c9dc 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -24,6 +24,7 @@ using osu.Framework.Input;
using osu.Framework.Logging;
using osu.Game.Audio;
using osu.Game.Database;
+using osu.Game.Graphics.Containers;
using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.IO;
@@ -189,7 +190,7 @@ namespace osu.Game
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
};
- base.Content.Add(new DrawSizePreservingFillContainer { Child = MenuCursorContainer });
+ base.Content.Add(new ScalingContainer(ScalingMode.Everything) { Child = MenuCursorContainer });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
@@ -247,7 +248,8 @@ namespace osu.Game
var extension = Path.GetExtension(paths.First())?.ToLowerInvariant();
foreach (var importer in fileImporters)
- if (importer.HandledExtensions.Contains(extension)) importer.Import(paths);
+ if (importer.HandledExtensions.Contains(extension))
+ importer.Import(paths);
}
public string[] HandledExtensions => fileImporters.SelectMany(i => i.HandledExtensions).ToArray();
diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSection.cs b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs
index 94ee9d4bf6..c02215d690 100644
--- a/osu.Game/Overlays/Chat/Selection/ChannelSection.cs
+++ b/osu.Game/Overlays/Chat/Selection/ChannelSection.cs
@@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+using System;
using System.Collections.Generic;
using System.Linq;
using osuTK;
@@ -18,7 +19,7 @@ namespace osu.Game.Overlays.Chat.Selection
public readonly FillFlowContainer ChannelFlow;
public IEnumerable FilterableChildren => ChannelFlow.Children;
- public IEnumerable FilterTerms => new[] { Header };
+ public IEnumerable FilterTerms => Array.Empty();
public bool MatchingFilter
{
set
diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
index 804ddeabb4..d4f3e1b0ac 100644
--- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
@@ -77,7 +77,6 @@ namespace osu.Game.Overlays.Chat.Tabs
CloseButton.FadeIn(TRANSITION_LENGTH, Easing.OutQuint);
}
-
protected override void FadeInactive()
{
base.FadeInactive();
diff --git a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs
index b939483cd8..a645dd86bd 100644
--- a/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs
+++ b/osu.Game/Overlays/KeyBinding/GlobalKeyBindingsSection.cs
@@ -18,7 +18,6 @@ namespace osu.Game.Overlays.KeyBinding
Add(new InGameKeyBindingsSubsection(manager));
}
-
private class DefaultBindingsSubsection : KeyBindingsSubsection
{
protected override string Header => string.Empty;
diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
index 742a3830b4..915e96c0fa 100644
--- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
@@ -176,7 +176,6 @@ namespace osu.Game.Overlays.Mods
section.DeselectTypes(modTypes, immediate);
}
-
private SampleChannel sampleOn, sampleOff;
private void modButtonPressed(Mod selectedMod)
diff --git a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
index ad886c363b..41a4977a5a 100644
--- a/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
+++ b/osu.Game/Overlays/Profile/Sections/Historical/PaginatedMostPlayedBeatmapContainer.cs
@@ -49,7 +49,6 @@ namespace osu.Game.Overlays.Profile.Sections.Historical
Api.Queue(request);
}
-
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
index 685244e06b..d59e2e033e 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs
@@ -6,9 +6,14 @@ using System.Drawing;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Configuration;
+using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
+using osuTK.Graphics;
namespace osu.Game.Overlays.Settings.Sections.Graphics
{
@@ -16,24 +21,33 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
{
protected override string Header => "Layout";
- private FillFlowContainer letterboxSettings;
+ private FillFlowContainer> scalingSettings;
- private Bindable letterboxing;
+ private Bindable scalingMode;
private Bindable sizeFullscreen;
private OsuGameBase game;
private SettingsDropdown resolutionDropdown;
private SettingsEnumDropdown windowModeDropdown;
+ private Bindable scalingPositionX;
+ private Bindable scalingPositionY;
+ private Bindable scalingSizeX;
+ private Bindable scalingSizeY;
+
private const int transition_duration = 400;
[BackgroundDependencyLoader]
- private void load(FrameworkConfigManager config, OsuGameBase game)
+ private void load(FrameworkConfigManager config, OsuConfigManager osuConfig, OsuGameBase game)
{
this.game = game;
- letterboxing = config.GetBindable(FrameworkSetting.Letterboxing);
+ scalingMode = osuConfig.GetBindable(OsuSetting.Scaling);
sizeFullscreen = config.GetBindable(FrameworkSetting.SizeFullscreen);
+ scalingSizeX = osuConfig.GetBindable(OsuSetting.ScalingSizeX);
+ scalingSizeY = osuConfig.GetBindable(OsuSetting.ScalingSizeY);
+ scalingPositionX = osuConfig.GetBindable(OsuSetting.ScalingPositionX);
+ scalingPositionY = osuConfig.GetBindable(OsuSetting.ScalingPositionY);
Container resolutionSettingsContainer;
@@ -49,12 +63,19 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
},
- new SettingsCheckbox
+ new SettingsSlider
{
- LabelText = "Letterboxing",
- Bindable = letterboxing,
+ LabelText = "UI Scaling",
+ TransferValueOnCommit = true,
+ Bindable = osuConfig.GetBindable(OsuSetting.UIScale),
+ KeyboardStep = 0.01f
},
- letterboxSettings = new FillFlowContainer
+ new SettingsEnumDropdown
+ {
+ LabelText = "Screen Scaling",
+ Bindable = osuConfig.GetBindable(OsuSetting.Scaling),
+ },
+ scalingSettings = new FillFlowContainer>
{
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
@@ -62,25 +83,38 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
AutoSizeDuration = transition_duration,
AutoSizeEasing = Easing.OutQuint,
Masking = true,
-
- Children = new Drawable[]
+ Children = new []
{
- new SettingsSlider
+ new SettingsSlider
{
LabelText = "Horizontal position",
- Bindable = config.GetBindable(FrameworkSetting.LetterboxPositionX),
+ Bindable = scalingPositionX,
KeyboardStep = 0.01f
},
- new SettingsSlider
+ new SettingsSlider
{
LabelText = "Vertical position",
- Bindable = config.GetBindable(FrameworkSetting.LetterboxPositionY),
+ Bindable = scalingPositionY,
+ KeyboardStep = 0.01f
+ },
+ new SettingsSlider
+ {
+ LabelText = "Horizontal scale",
+ Bindable = scalingSizeX,
+ KeyboardStep = 0.01f
+ },
+ new SettingsSlider
+ {
+ LabelText = "Vertical scale",
+ Bindable = scalingSizeY,
KeyboardStep = 0.01f
},
}
},
};
+ scalingSettings.ForEach(s => bindPreviewEvent(s.Bindable));
+
var resolutions = getResolutions();
if (resolutions.Count > 1)
@@ -105,16 +139,46 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
}, true);
}
- letterboxing.BindValueChanged(isVisible =>
+ scalingMode.BindValueChanged(mode =>
{
- letterboxSettings.ClearTransforms();
- letterboxSettings.AutoSizeAxes = isVisible ? Axes.Y : Axes.None;
+ scalingSettings.ClearTransforms();
+ scalingSettings.AutoSizeAxes = mode != ScalingMode.Off ? Axes.Y : Axes.None;
- if (!isVisible)
- letterboxSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
+ if (mode == ScalingMode.Off)
+ scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint);
+
+ scalingSettings.ForEach(s => s.TransferValueOnCommit = mode == ScalingMode.Everything);
}, true);
}
+ ///
+ /// Create a delayed bindable which only updates when a condition is met.
+ ///
+ /// The config bindable.
+ /// A bindable which will propagate updates with a delay.
+ private void bindPreviewEvent(Bindable bindable)
+ {
+ bindable.ValueChanged += v =>
+ {
+ switch (scalingMode.Value)
+ {
+ case ScalingMode.Gameplay:
+ showPreview();
+ break;
+ }
+ };
+ }
+
+ private Drawable preview;
+ private void showPreview()
+ {
+ if (preview?.IsAlive != true)
+ game.Add(preview = new ScalingPreview());
+
+ preview.FadeOutFromOne(1500);
+ preview.Expire();
+ }
+
private IReadOnlyList getResolutions()
{
var resolutions = new List { new Size(9999, 9999) };
@@ -132,6 +196,24 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
return resolutions;
}
+ private class ScalingPreview : ScalingContainer
+ {
+ public ScalingPreview()
+ {
+ Child = new Box
+ {
+ Colour = Color4.White,
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0.5f,
+ };
+ }
+ }
+
+ private class UIScaleSlider : OsuSliderBar
+ {
+ public override string TooltipText => base.TooltipText + "x";
+ }
+
private class ResolutionSettingsDropdown : SettingsDropdown
{
protected override OsuDropdown CreateDropdown() => new ResolutionDropdownControl { Items = Items };
diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
index c4d180790c..e5cde37254 100644
--- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
@@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Input;
-using osu.Framework.Input.Events;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
@@ -78,66 +77,15 @@ namespace osu.Game.Overlays.Settings.Sections.Input
private class SensitivitySetting : SettingsSlider
{
- public override Bindable Bindable
- {
- get { return ((SensitivitySlider)Control).Sensitivity; }
-
- set
- {
- BindableDouble doubleValue = (BindableDouble)value;
-
- // create a second layer of bindable so we can only handle state changes when not being dragged.
- ((SensitivitySlider)Control).Sensitivity = doubleValue;
-
- // this bindable will still act as the "interactive" bindable displayed during a drag.
- base.Bindable = new BindableDouble(doubleValue.Value)
- {
- Default = doubleValue.Default,
- MinValue = doubleValue.MinValue,
- MaxValue = doubleValue.MaxValue
- };
-
- // one-way binding to update the sliderbar with changes from external actions.
- doubleValue.DisabledChanged += disabled => base.Bindable.Disabled = disabled;
- doubleValue.ValueChanged += newValue => base.Bindable.Value = newValue;
- }
- }
-
public SensitivitySetting()
{
KeyboardStep = 0.01f;
+ TransferValueOnCommit = true;
}
}
private class SensitivitySlider : OsuSliderBar
{
- public Bindable Sensitivity;
-
- public SensitivitySlider()
- {
- Current.ValueChanged += newValue =>
- {
- if (!isDragging && Sensitivity != null)
- Sensitivity.Value = newValue;
- };
- }
-
- private bool isDragging;
-
- protected override bool OnDragStart(DragStartEvent e)
- {
- isDragging = true;
- return base.OnDragStart(e);
- }
-
- protected override bool OnDragEnd(DragEndEvent e)
- {
- isDragging = false;
- Current.TriggerChange();
-
- return base.OnDragEnd(e);
- }
-
public override string TooltipText => Current.Disabled ? "Enable raw input to adjust sensitivity" : Current.Value.ToString(@"0.##x");
}
}
diff --git a/osu.Game/Overlays/Settings/SettingsLabel.cs b/osu.Game/Overlays/Settings/SettingsLabel.cs
deleted file mode 100644
index 2df4073191..0000000000
--- a/osu.Game/Overlays/Settings/SettingsLabel.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Game.Graphics;
-
-namespace osu.Game.Overlays.Settings
-{
- public class SettingsLabel : SettingsItem
- {
- protected override Drawable CreateControl() => null;
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colour)
- {
- Colour = colour.Gray6;
- }
- }
-}
diff --git a/osu.Game/Overlays/Settings/SettingsSlider.cs b/osu.Game/Overlays/Settings/SettingsSlider.cs
index a3698c36e6..39a974dd2e 100644
--- a/osu.Game/Overlays/Settings/SettingsSlider.cs
+++ b/osu.Game/Overlays/Settings/SettingsSlider.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
-using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
@@ -23,14 +22,16 @@ namespace osu.Game.Overlays.Settings
RelativeSizeAxes = Axes.X
};
- public float KeyboardStep;
-
- [BackgroundDependencyLoader]
- private void load()
+ public bool TransferValueOnCommit
{
- var slider = Control as U;
- if (slider != null)
- slider.KeyboardStep = KeyboardStep;
+ get => ((U)Control).TransferValueOnCommit;
+ set => ((U)Control).TransferValueOnCommit = value;
+ }
+
+ public float KeyboardStep
+ {
+ get => ((U)Control).KeyboardStep;
+ set => ((U)Control).KeyboardStep = value;
}
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
index 85eb29033e..7b6c89f0f5 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs
@@ -124,7 +124,6 @@ namespace osu.Game.Rulesets.Objects.Legacy
// osu-stable treated the first span of the slider as a repeat, but no repeats are happening
repeatCount = Math.Max(0, repeatCount - 1);
-
if (split.Length > 7)
length = Convert.ToDouble(split[7], CultureInfo.InvariantCulture);
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index b863566967..78cc3592c7 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Scoring
[Column(TypeName="DECIMAL(1,4)")]
public double Accuracy { get; set; }
- [JsonIgnore]
+ [JsonProperty(@"pp")]
public double? PP { get; set; }
[JsonProperty("max_combo")]
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
new file mode 100644
index 0000000000..c097d25178
--- /dev/null
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenBlack.cs
@@ -0,0 +1,27 @@
+// Copyright (c) 2007-2018 ppy Pty Ltd .
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Screens;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Backgrounds
+{
+ public class BackgroundScreenBlack : BackgroundScreen
+ {
+ public BackgroundScreenBlack()
+ {
+ Child = new Box
+ {
+ Colour = Color4.Black,
+ RelativeSizeAxes = Axes.Both,
+ };
+ }
+
+ protected override void OnEntering(Screen last)
+ {
+ Show();
+ }
+ }
+}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
index 989883c8b3..f924cf9805 100644
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
+++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs
@@ -2,10 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
+using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using osu.Framework.Threading;
using osu.Game.Graphics.Backgrounds;
+using osu.Game.Online.API;
+using osu.Game.Skinning;
+using osu.Game.Users;
namespace osu.Game.Screens.Backgrounds
{
@@ -16,11 +20,21 @@ namespace osu.Game.Screens.Backgrounds
private string backgroundName => $@"Menu/menu-background-{currentDisplay % background_count + 1}";
+ private Bindable user;
+ private Bindable skin;
+
[BackgroundDependencyLoader]
- private void load()
+ private void load(IAPIProvider api, SkinManager skinManager)
{
+ user = api.LocalUser.GetBoundCopy();
+ skin = skinManager.CurrentSkin.GetBoundCopy();
+
+ user.ValueChanged += _ => Next();
+ skin.ValueChanged += _ => Next();
+
currentDisplay = RNG.Next(0, background_count);
- display(new Background(backgroundName));
+
+ Next();
}
private void display(Background newBackground)
@@ -39,8 +53,33 @@ namespace osu.Game.Screens.Backgrounds
nextTask?.Cancel();
nextTask = Scheduler.AddDelayed(() =>
{
- LoadComponentAsync(new Background(backgroundName) { Depth = currentDisplay }, display);
+ Background background;
+
+ if (user.Value?.IsSupporter ?? false)
+ background = new SkinnedBackground(skin.Value, backgroundName);
+ else
+ background = new Background(backgroundName);
+
+ background.Depth = currentDisplay;
+
+ LoadComponentAsync(background, display);
}, 100);
}
+
+ private class SkinnedBackground : Background
+ {
+ private readonly Skin skin;
+
+ public SkinnedBackground(Skin skin, string fallbackTextureName) : base(fallbackTextureName)
+ {
+ this.skin = skin;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Sprite.Texture = skin.GetTexture("menu-background") ?? Sprite.Texture;
+ }
+ }
}
}
diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenEmpty.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenEmpty.cs
deleted file mode 100644
index 5e08db8907..0000000000
--- a/osu.Game/Screens/Backgrounds/BackgroundScreenEmpty.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2007-2018 ppy Pty Ltd .
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-namespace osu.Game.Screens.Backgrounds
-{
- public class BackgroundScreenEmpty : BackgroundScreen
- {
- }
-}
diff --git a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs
index 129ea2bf7d..48ef27add3 100644
--- a/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs
+++ b/osu.Game/Screens/Edit/Components/TimeInfoContainer.cs
@@ -17,7 +17,6 @@ namespace osu.Game.Screens.Edit.Components
public TimeInfoContainer()
{
-
Children = new Drawable[]
{
trackTimer = new OsuSpriteText
diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
index aa63b02013..373f4d1682 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
@@ -238,11 +238,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
case Key.Right:
beatDivisor.Next();
- OnUserChange();
+ OnUserChange(Current);
return true;
case Key.Left:
beatDivisor.Previous();
- OnUserChange();
+ OnUserChange(Current);
return true;
default:
return false;
@@ -279,7 +279,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
var xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
CurrentNumber.Value = availableDivisors.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First();
- OnUserChange();
+ OnUserChange(Current);
}
private float getMappedPosition(float divisor) => (float)Math.Pow((divisor - 1) / (availableDivisors.Last() - 1), 0.90f);
diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs
index aa30b1a9f5..05ba1ab732 100644
--- a/osu.Game/Screens/Edit/EditorClock.cs
+++ b/osu.Game/Screens/Edit/EditorClock.cs
@@ -57,7 +57,7 @@ namespace osu.Game.Screens.Edit
// Depending on beatSnapLength, we may snap to a beat that is beyond timingPoint's end time, but we want to instead snap to
// the next timing point's start time
- var nextTimingPoint = ControlPointInfo.TimingPoints.FirstOrDefault(t => t.Time > timingPoint.Time);
+ var nextTimingPoint = ControlPointInfo.TimingPoints.Find(t => t.Time > timingPoint.Time);
if (position > nextTimingPoint?.Time)
position = nextTimingPoint.Time;
@@ -123,7 +123,7 @@ namespace osu.Game.Screens.Edit
if (seekTime < timingPoint.Time && timingPoint != ControlPointInfo.TimingPoints.First())
seekTime = timingPoint.Time;
- var nextTimingPoint = ControlPointInfo.TimingPoints.FirstOrDefault(t => t.Time > timingPoint.Time);
+ var nextTimingPoint = ControlPointInfo.TimingPoints.Find(t => t.Time > timingPoint.Time);
if (seekTime > nextTimingPoint?.Time)
seekTime = nextTimingPoint.Time;
diff --git a/osu.Game/Screens/Menu/Intro.cs b/osu.Game/Screens/Menu/Intro.cs
index fa01411a0f..8d9cd8dbe9 100644
--- a/osu.Game/Screens/Menu/Intro.cs
+++ b/osu.Game/Screens/Menu/Intro.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Menu
public override bool CursorVisible => false;
- protected override BackgroundScreen CreateBackground() => new BackgroundScreenEmpty();
+ protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack();
private Bindable menuVoice;
private Bindable menuMusic;
diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs
index ec5528b13f..188e95ced5 100644
--- a/osu.Game/Screens/Menu/MenuSideFlashes.cs
+++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs
@@ -58,6 +58,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.CentreLeft,
RelativeSizeAxes = Axes.Y,
Width = box_width * 2,
+ Height = 1.5f,
// align off-screen to make sure our edges don't become visible during parallax.
X = -box_width,
Alpha = 0,
@@ -70,6 +71,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y,
Width = box_width * 2,
+ Height = 1.5f,
X = box_width,
Alpha = 0,
Blending = BlendingMode.Additive,
diff --git a/osu.Game/Screens/Multi/IRoomManager.cs b/osu.Game/Screens/Multi/IRoomManager.cs
index f0dbcb0e71..6af8a35208 100644
--- a/osu.Game/Screens/Multi/IRoomManager.cs
+++ b/osu.Game/Screens/Multi/IRoomManager.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Screens.Multi
///
/// All the active s.
///
- IBindableCollection Rooms { get; }
+ IBindableList Rooms { get; }
///
/// Creates a new .
diff --git a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs
index 34fc7fe886..228bacf3f3 100644
--- a/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs
+++ b/osu.Game/Screens/Multi/Lounge/Components/ParticipantInfo.cs
@@ -93,10 +93,14 @@ namespace osu.Game.Screens.Multi.Lounge.Components
Host.BindValueChanged(v =>
{
hostText.Clear();
- hostText.AddText("hosted by ");
- hostText.AddLink(v.Username, null, LinkAction.OpenUserProfile, v.Id.ToString(), "Open profile", s => s.Font = "Exo2.0-BoldItalic");
+ flagContainer.Clear();
- flagContainer.Child = new DrawableFlag(v.Country) { RelativeSizeAxes = Axes.Both };
+ if (v != null)
+ {
+ hostText.AddText("hosted by ");
+ hostText.AddLink(v.Username, null, LinkAction.OpenUserProfile, v.Id.ToString(), "Open profile", s => s.Font = "Exo2.0-BoldItalic");
+ flagContainer.Child = new DrawableFlag(v.Country) { RelativeSizeAxes = Axes.Both };
+ }
});
ParticipantCount.BindValueChanged(v => summary.Text = $"{v:#,0}{" participant".Pluralize(v == 1)}");
diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs
index 47f5182c39..665481934e 100644
--- a/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs
+++ b/osu.Game/Screens/Multi/Lounge/Components/RoomInspector.cs
@@ -1,7 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd .
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-using System.Linq;
+using System;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
@@ -13,8 +13,9 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
-using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer;
using osu.Game.Screens.Multi.Components;
using osu.Game.Users;
@@ -37,11 +38,10 @@ namespace osu.Game.Screens.Multi.Lounge.Components
private Box statusStrip;
private UpdateableBeatmapBackgroundSprite background;
private ParticipantCountDisplay participantCount;
- private FillFlowContainer topFlow, participantsFlow;
private OsuSpriteText name, status;
private BeatmapTypeInfo beatmapTypeInfo;
- private ScrollContainer participantsScroll;
private ParticipantInfo participantInfo;
+ private MatchParticipants participants;
[Resolved]
private BeatmapManager beatmaps { get; set; }
@@ -58,141 +58,141 @@ namespace osu.Game.Screens.Multi.Lounge.Components
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"343138"),
},
- topFlow = new FillFlowContainer
+ new GridContainer
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ RelativeSizeAxes = Axes.Both,
+ RowDimensions = new[]
{
- new Container
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension(GridSizeMode.Distributed),
+ },
+ Content = new[]
+ {
+ new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- Height = 200,
- Masking = true,
- Children = new Drawable[]
+ new FillFlowContainer
{
- background = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both },
- new Box
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.5f), Color4.Black.Opacity(0)),
- },
- new Container
- {
- RelativeSizeAxes = Axes.Both,
- Padding = new MarginPadding(20),
- Children = new Drawable[]
+ new Container
{
- participantCount = new ParticipantCountDisplay
+ RelativeSizeAxes = Axes.X,
+ Height = 200,
+ Masking = true,
+ Children = new Drawable[]
{
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
+ background = new UpdateableBeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both },
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.5f), Color4.Black.Opacity(0)),
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Padding = new MarginPadding(20),
+ Children = new Drawable[]
+ {
+ participantCount = new ParticipantCountDisplay
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ },
+ name = new OsuSpriteText
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ TextSize = 30,
+ },
+ },
+ },
},
- name = new OsuSpriteText
+ },
+ statusStrip = new Box
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 5,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
{
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
- TextSize = 30,
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.FromHex(@"28242d"),
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ LayoutDuration = transition_duration,
+ Padding = contentPadding,
+ Spacing = new Vector2(0f, 5f),
+ Children = new Drawable[]
+ {
+ status = new OsuSpriteText
+ {
+ TextSize = 14,
+ Font = @"Exo2.0-Bold",
+ },
+ beatmapTypeInfo = new BeatmapTypeInfo(),
+ },
+ },
+ },
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = contentPadding,
+ Children = new Drawable[]
+ {
+ participantInfo = new ParticipantInfo(),
},
},
},
},
},
- statusStrip = new Box
+ new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- Height = 5,
- },
- new Container
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Children = new Drawable[]
+ participants = new MatchParticipants
{
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"28242d"),
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- LayoutDuration = transition_duration,
- Padding = contentPadding,
- Spacing = new Vector2(0f, 5f),
- Children = new Drawable[]
- {
- status = new OsuSpriteText
- {
- TextSize = 14,
- Font = @"Exo2.0-Bold",
- },
- beatmapTypeInfo = new BeatmapTypeInfo(),
- },
- },
- },
- },
- new Container
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = contentPadding,
- Children = new Drawable[]
- {
- participantInfo = new ParticipantInfo(),
- },
- },
- },
- },
- participantsScroll = new OsuScrollContainer
- {
- Anchor = Anchor.BottomLeft,
- Origin = Anchor.BottomLeft,
- RelativeSizeAxes = Axes.X,
- Padding = new MarginPadding { Top = contentPadding.Top, Left = 38, Right = 37 },
- Children = new[]
- {
- participantsFlow = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- LayoutDuration = transition_duration,
- Spacing = new Vector2(5f),
- },
- },
- },
+ RelativeSizeAxes = Axes.Both,
+ }
+ }
+ }
+ }
};
participantInfo.Host.BindTo(bindings.Host);
participantInfo.ParticipantCount.BindTo(bindings.ParticipantCount);
participantInfo.Participants.BindTo(bindings.Participants);
-
participantCount.Participants.BindTo(bindings.Participants);
participantCount.ParticipantCount.BindTo(bindings.ParticipantCount);
participantCount.MaxParticipants.BindTo(bindings.MaxParticipants);
-
beatmapTypeInfo.Beatmap.BindTo(bindings.CurrentBeatmap);
beatmapTypeInfo.Ruleset.BindTo(bindings.CurrentRuleset);
beatmapTypeInfo.Type.BindTo(bindings.Type);
background.Beatmap.BindTo(bindings.CurrentBeatmap);
-
bindings.Status.BindValueChanged(displayStatus);
- bindings.Participants.BindValueChanged(p => participantsFlow.ChildrenEnumerable = p.Select(u => new UserTile(u)));
bindings.Name.BindValueChanged(n => name.Text = n);
-
Room.BindValueChanged(updateRoom, true);
}
private void updateRoom(Room room)
{
bindings.Room = room;
+ participants.Room = room;
if (room != null)
{
- participantsFlow.FadeIn(transition_duration);
participantCount.FadeIn(transition_duration);
beatmapTypeInfo.FadeIn(transition_duration);
name.FadeIn(transition_duration);
@@ -200,7 +200,6 @@ namespace osu.Game.Screens.Multi.Lounge.Components
}
else
{
- participantsFlow.FadeOut(transition_duration);
participantCount.FadeOut(transition_duration);
beatmapTypeInfo.FadeOut(transition_duration);
name.FadeOut(transition_duration);
@@ -210,13 +209,6 @@ namespace osu.Game.Screens.Multi.Lounge.Components
}
}
- protected override void UpdateAfterChildren()
- {
- base.UpdateAfterChildren();
-
- participantsScroll.Height = DrawHeight - topFlow.DrawHeight;
- }
-
private void displayStatus(RoomStatus s)
{
status.Text = s.Message;
@@ -226,39 +218,119 @@ namespace osu.Game.Screens.Multi.Lounge.Components
status.FadeColour(c, transition_duration);
}
- private class UserTile : Container, IHasTooltip
- {
- private readonly User user;
-
- public string TooltipText => user.Username;
-
- public UserTile(User user)
- {
- this.user = user;
- Size = new Vector2(70f);
- CornerRadius = 5f;
- Masking = true;
-
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"27252d"),
- },
- new UpdateableAvatar
- {
- RelativeSizeAxes = Axes.Both,
- User = user,
- },
- };
- }
- }
-
private class RoomStatusNoneSelected : RoomStatus
{
public override string Message => @"No Room Selected";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray8;
}
+
+ private class MatchParticipants : CompositeDrawable
+ {
+ private Room room;
+ private readonly FillFlowContainer fill;
+
+ public Room Room
+ {
+ get { return room; }
+ set
+ {
+ if (room == value)
+ return;
+
+ room = value;
+ updateParticipants();
+ }
+ }
+
+ public MatchParticipants()
+ {
+ Padding = new MarginPadding { Horizontal = 10 };
+
+ InternalChild = new ScrollContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = fill = new FillFlowContainer
+ {
+ Spacing = new Vector2(10),
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Full,
+ }
+ };
+ }
+
+ [Resolved]
+ private APIAccess api { get; set; }
+
+ private GetRoomScoresRequest request;
+
+ private void updateParticipants()
+ {
+ var roomId = room?.RoomID.Value ?? 0;
+
+ request?.Cancel();
+
+ // nice little progressive fade
+ int time = 500;
+ foreach (var c in fill.Children)
+ {
+ c.Delay(500 - time).FadeOut(time, Easing.Out);
+ time = Math.Max(20, time - 20);
+ c.Expire();
+ }
+
+ if (roomId == 0) return;
+
+ request = new GetRoomScoresRequest(roomId);
+ request.Success += scores =>
+ {
+ if (roomId != room.RoomID.Value)
+ return;
+
+ fill.Clear();
+ foreach (var s in scores)
+ fill.Add(new UserTile(s.User));
+
+ fill.FadeInFromZero(1000, Easing.OutQuint);
+ };
+
+ api.Queue(request);
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ request?.Cancel();
+ base.Dispose(isDisposing);
+ }
+
+ private class UserTile : CompositeDrawable, IHasTooltip
+ {
+ private readonly User user;
+
+ public string TooltipText => user.Username;
+
+ public UserTile(User user)
+ {
+ this.user = user;
+ Size = new Vector2(70f);
+ CornerRadius = 5f;
+ Masking = true;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = OsuColour.FromHex(@"27252d"),
+ },
+ new UpdateableAvatar
+ {
+ RelativeSizeAxes = Axes.Both,
+ User = user,
+ },
+ };
+ }
+ }
+ }
}
}
diff --git a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
index 5133e96a52..4ad8154090 100644
--- a/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
+++ b/osu.Game/Screens/Multi/Lounge/Components/RoomsContainer.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
private readonly Bindable selectedRoom = new Bindable();
public IBindable SelectedRoom => selectedRoom;
- private readonly IBindableCollection rooms = new BindableCollection();
+ private readonly IBindableList rooms = new BindableList();
private readonly FillFlowContainer roomFlow;
public IReadOnlyList Rooms => roomFlow;
diff --git a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs
index 864191105f..5ac0453373 100644
--- a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs
+++ b/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs
@@ -16,17 +16,18 @@ namespace osu.Game.Screens.Multi.Match.Components
{
public Action> ScoresLoaded;
- private readonly Room room;
-
- public MatchLeaderboard(Room room)
+ public Room Room
{
- this.room = room;
+ get => bindings.Room;
+ set => bindings.Room = value;
}
+ private readonly RoomBindings bindings = new RoomBindings();
+
[BackgroundDependencyLoader]
private void load()
{
- room.RoomID.BindValueChanged(id =>
+ bindings.RoomID.BindValueChanged(id =>
{
if (id == null)
return;
@@ -38,10 +39,10 @@ namespace osu.Game.Screens.Multi.Match.Components
protected override APIRequest FetchScores(Action> scoresCallback)
{
- if (room.RoomID == null)
+ if (bindings.RoomID.Value == null)
return null;
- var req = new GetRoomScoresRequest(room.RoomID.Value ?? 0);
+ var req = new GetRoomScoresRequest(bindings.RoomID.Value ?? 0);
req.Success += r =>
{
diff --git a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
index 55a5a2c85e..a7932e1131 100644
--- a/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
+++ b/osu.Game/Screens/Multi/Match/MatchSubScreen.cs
@@ -51,6 +51,8 @@ namespace osu.Game.Screens.Multi.Match
MatchChatDisplay chat;
Components.Header header;
+ Info info;
+ GridContainer bottomRow;
MatchSettingsOverlay settings;
Children = new Drawable[]
@@ -61,20 +63,21 @@ namespace osu.Game.Screens.Multi.Match
Content = new[]
{
new Drawable[] { header = new Components.Header(room) { Depth = -1 } },
- new Drawable[] { new Info(room) { OnStart = onStart } },
+ new Drawable[] { info = new Info(room) { OnStart = onStart } },
new Drawable[]
{
- new GridContainer
+ bottomRow = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
{
- leaderboard = new MatchLeaderboard(room)
+ leaderboard = new MatchLeaderboard
{
Padding = new MarginPadding(10),
- RelativeSizeAxes = Axes.Both
+ RelativeSizeAxes = Axes.Both,
+ Room = room
},
new Container
{
@@ -108,10 +111,19 @@ namespace osu.Game.Screens.Multi.Match
header.OnRequestSelectBeatmap = () => Push(new MatchSongSelect { Selected = addPlaylistItem });
header.Tabs.Current.ValueChanged += t =>
{
+ const float fade_duration = 500;
if (t is SettingsMatchPage)
+ {
settings.Show();
+ info.FadeOut(fade_duration, Easing.OutQuint);
+ bottomRow.FadeOut(fade_duration, Easing.OutQuint);
+ }
else
+ {
settings.Hide();
+ info.FadeIn(fade_duration, Easing.OutQuint);
+ bottomRow.FadeIn(fade_duration, Easing.OutQuint);
+ }
};
chat.Exit += Exit;
diff --git a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs
index 54528e5503..44f5f11c93 100644
--- a/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs
+++ b/osu.Game/Screens/Multi/Ranking/Pages/RoomLeaderboardPage.cs
@@ -103,8 +103,8 @@ namespace osu.Game.Screens.Multi.Ranking.Pages
public class ResultsMatchLeaderboard : MatchLeaderboard
{
public ResultsMatchLeaderboard(Room room)
- : base(room)
{
+ Room = room;
}
protected override bool FadeTop => true;
diff --git a/osu.Game/Screens/Multi/RoomBindings.cs b/osu.Game/Screens/Multi/RoomBindings.cs
index dc2547268d..e7f9e323bc 100644
--- a/osu.Game/Screens/Multi/RoomBindings.cs
+++ b/osu.Game/Screens/Multi/RoomBindings.cs
@@ -39,6 +39,7 @@ namespace osu.Game.Screens.Multi
if (room != null)
{
+ RoomID.UnbindFrom(room.RoomID);
Name.UnbindFrom(room.Name);
Host.UnbindFrom(room.Host);
Status.UnbindFrom(room.Status);
@@ -52,22 +53,20 @@ namespace osu.Game.Screens.Multi
Duration.UnbindFrom(room.Duration);
}
- room = value;
+ room = value ?? new Room();
- if (room != null)
- {
- Name.BindTo(room.Name);
- Host.BindTo(room.Host);
- Status.BindTo(room.Status);
- Type.BindTo(room.Type);
- Playlist.BindTo(room.Playlist);
- Participants.BindTo(room.Participants);
- ParticipantCount.BindTo(room.ParticipantCount);
- MaxParticipants.BindTo(room.MaxParticipants);
- EndDate.BindTo(room.EndDate);
- Availability.BindTo(room.Availability);
- Duration.BindTo(room.Duration);
- }
+ RoomID.BindTo(room.RoomID);
+ Name.BindTo(room.Name);
+ Host.BindTo(room.Host);
+ Status.BindTo(room.Status);
+ Type.BindTo(room.Type);
+ Playlist.BindTo(room.Playlist);
+ Participants.BindTo(room.Participants);
+ ParticipantCount.BindTo(room.ParticipantCount);
+ MaxParticipants.BindTo(room.MaxParticipants);
+ EndDate.BindTo(room.EndDate);
+ Availability.BindTo(room.Availability);
+ Duration.BindTo(room.Duration);
}
}
@@ -82,11 +81,12 @@ namespace osu.Game.Screens.Multi
currentRuleset.Value = playlistItem?.Ruleset;
}
+ public readonly Bindable RoomID = new Bindable();
public readonly Bindable Name = new Bindable();
public readonly Bindable Host = new Bindable();
public readonly Bindable Status = new Bindable();
public readonly Bindable Type = new Bindable();
- public readonly BindableCollection Playlist = new BindableCollection();
+ public readonly BindableList Playlist = new BindableList();
public readonly Bindable> Participants = new Bindable>();
public readonly Bindable ParticipantCount = new Bindable();
public readonly Bindable MaxParticipants = new Bindable();
diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs
index fab19c3fd7..1f95401905 100644
--- a/osu.Game/Screens/Multi/RoomManager.cs
+++ b/osu.Game/Screens/Multi/RoomManager.cs
@@ -21,8 +21,8 @@ namespace osu.Game.Screens.Multi
{
public event Action RoomsUpdated;
- private readonly BindableCollection rooms = new BindableCollection();
- public IBindableCollection Rooms => rooms;
+ private readonly BindableList rooms = new BindableList();
+ public IBindableList Rooms => rooms;
private Room currentRoom;
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index 11cee98bdf..cc665d99a1 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -24,8 +24,6 @@ namespace osu.Game.Screens.Play
{
private const int duration = 100;
- private readonly Container content;
-
public readonly KeyCounterCollection KeyCounter;
public readonly RollingCounter ComboCounter;
public readonly ScoreCounter ScoreCounter;
@@ -37,6 +35,7 @@ namespace osu.Game.Screens.Play
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
private Bindable showHud;
+ private readonly Container visibilityContainer;
private readonly BindableBool replayLoaded = new BindableBool();
private static bool hasShownNotificationOnce;
@@ -45,34 +44,35 @@ namespace osu.Game.Screens.Play
{
RelativeSizeAxes = Axes.Both;
- Add(content = new Container
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.Both,
- AlwaysPresent = true, // The hud may be hidden but certain elements may need to still be updated
- Children = new Drawable[]
+ visibilityContainer = new Container {
+ RelativeSizeAxes = Axes.Both,
+ AlwaysPresent = true, // The hud may be hidden but certain elements may need to still be updated
+ Children = new Drawable[] {
+ ComboCounter = CreateComboCounter(),
+ ScoreCounter = CreateScoreCounter(),
+ AccuracyCounter = CreateAccuracyCounter(),
+ HealthDisplay = CreateHealthDisplay(),
+ Progress = CreateProgress(),
+ ModDisplay = CreateModsContainer(),
+ PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
+ }
+ },
+ new FillFlowContainer
{
- ComboCounter = CreateComboCounter(),
- ScoreCounter = CreateScoreCounter(),
- AccuracyCounter = CreateAccuracyCounter(),
- HealthDisplay = CreateHealthDisplay(),
- Progress = CreateProgress(),
- ModDisplay = CreateModsContainer(),
- PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
- new FillFlowContainer
+ Anchor = Anchor.BottomRight,
+ Origin = Anchor.BottomRight,
+ Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- Anchor = Anchor.BottomRight,
- Origin = Anchor.BottomRight,
- Position = -new Vector2(5, TwoLayerButton.SIZE_RETRACTED.Y),
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
- {
- KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock),
- HoldToQuit = CreateHoldForMenuButton(),
- }
+ KeyCounter = CreateKeyCounter(adjustableClock as IFrameBasedClock),
+ HoldToQuit = CreateHoldForMenuButton(),
}
}
- });
+ };
BindProcessor(scoreProcessor);
BindRulesetContainer(rulesetContainer);
@@ -91,7 +91,7 @@ namespace osu.Game.Screens.Play
private void load(OsuConfigManager config, NotificationOverlay notificationOverlay)
{
showHud = config.GetBindable(OsuSetting.ShowInterface);
- showHud.ValueChanged += hudVisibility => content.FadeTo(hudVisibility ? 1 : 0, duration);
+ showHud.ValueChanged += hudVisibility => visibilityContainer.FadeTo(hudVisibility ? 1 : 0, duration);
showHud.TriggerChange();
if (!showHud && !hasShownNotificationOnce)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 14dc644100..d5c99f5729 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -20,6 +20,7 @@ using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Online.API;
using osu.Game.Overlays;
@@ -179,10 +180,13 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both,
Alpha = 0,
},
- new LocalSkinOverrideContainer(working.Skin)
+ new ScalingContainer(ScalingMode.Gameplay)
{
- RelativeSizeAxes = Axes.Both,
- Child = RulesetContainer
+ Child = new LocalSkinOverrideContainer(working.Skin)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Child = RulesetContainer
+ }
},
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, ScoreProcessor)
{
@@ -191,7 +195,10 @@ namespace osu.Game.Screens.Play
ProcessCustomClock = false,
Breaks = beatmap.Breaks
},
- RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
+ new ScalingContainer(ScalingMode.Gameplay)
+ {
+ Child = RulesetContainer.Cursor?.CreateProxy() ?? new Container(),
+ },
hudOverlay = new HUDOverlay(ScoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
{
Clock = Clock, // hud overlay doesn't want to use the audio clock directly
diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs
index e5a6dd2db1..577a1325a9 100644
--- a/osu.Game/Screens/Play/SkipOverlay.cs
+++ b/osu.Game/Screens/Play/SkipOverlay.cs
@@ -46,10 +46,10 @@ namespace osu.Game.Screens.Play
State = Visibility.Visible;
RelativePositionAxes = Axes.Both;
- RelativeSizeAxes = Axes.Both;
+ RelativeSizeAxes = Axes.X;
Position = new Vector2(0.5f, 0.7f);
- Size = new Vector2(1, 0.14f);
+ Size = new Vector2(1, 100);
Origin = Anchor.Centre;
}
diff --git a/osu.Game/Screens/Play/SongProgressBar.cs b/osu.Game/Screens/Play/SongProgressBar.cs
index 1f0c4936a5..b06a34e603 100644
--- a/osu.Game/Screens/Play/SongProgressBar.cs
+++ b/osu.Game/Screens/Play/SongProgressBar.cs
@@ -112,6 +112,6 @@ namespace osu.Game.Screens.Play
handleBase.X = xFill;
}
- protected override void OnUserChange() => OnSeek?.Invoke(Current);
+ protected override void OnUserChange(double value) => OnSeek?.Invoke(value);
}
}
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index 348394c1f5..63c97f9bd5 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -101,7 +101,6 @@ namespace osu.Game.Screens.Select
private readonly Container scrollableContent;
-
public Bindable RightClickScrollingEnabled = new Bindable();
public Bindable RandomAlgorithm = new Bindable();
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index f65cc0e49d..2f212a2564 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -297,14 +297,14 @@ namespace osu.Game.Screens.Select
/// Whether to trigger .
public void FinaliseSelection(BeatmapInfo beatmap = null, bool performStartAction = true)
{
- // avoid attempting to continue before a selection has been obtained.
- // this could happen via a user interaction while the carousel is still in a loading state.
- if (Carousel.SelectedBeatmap == null) return;
-
// if we have a pending filter operation, we want to run it now.
// it could change selection (ie. if the ruleset has been changed).
Carousel.FlushPendingFilterOperations();
+ // avoid attempting to continue before a selection has been obtained.
+ // this could happen via a user interaction while the carousel is still in a loading state.
+ if (Carousel.SelectedBeatmap == null) return;
+
if (beatmap != null)
Carousel.SelectBeatmap(beatmap);
diff --git a/osu.Game/Screens/Tournament/Drawings.cs b/osu.Game/Screens/Tournament/Drawings.cs
index 0a428ea289..754f34f00f 100644
--- a/osu.Game/Screens/Tournament/Drawings.cs
+++ b/osu.Game/Screens/Tournament/Drawings.cs
@@ -327,7 +327,7 @@ namespace osu.Game.Screens.Tournament
continue;
// ReSharper disable once AccessToModifiedClosure
- DrawingsTeam teamToAdd = allTeams.FirstOrDefault(t => t.FullName == line);
+ DrawingsTeam teamToAdd = allTeams.Find(t => t.FullName == line);
if (teamToAdd == null)
continue;
diff --git a/osu.Game/Skinning/ISkinSource.cs b/osu.Game/Skinning/ISkinSource.cs
index 609f8e4ac4..53ac4c3454 100644
--- a/osu.Game/Skinning/ISkinSource.cs
+++ b/osu.Game/Skinning/ISkinSource.cs
@@ -21,8 +21,6 @@ namespace osu.Game.Skinning
SampleChannel GetSample(string sampleName);
- TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class;
-
- TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct;
+ TValue GetValue(Func query) where TConfiguration : SkinConfiguration;
}
}
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index 25a9813ad6..23367c58c9 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -102,7 +102,7 @@ namespace osu.Game.Skinning
string lastPiece = filename.Split('/').Last();
- var file = source.Files.FirstOrDefault(f =>
+ var file = source.Files.Find(f =>
string.Equals(hasExtension ? f.Filename : Path.ChangeExtension(f.Filename, null), lastPiece, StringComparison.InvariantCultureIgnoreCase));
return file?.FileInfo.StoragePath;
}
diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs
index 67a031fb50..9fbd88596d 100644
--- a/osu.Game/Skinning/LegacySkinDecoder.cs
+++ b/osu.Game/Skinning/LegacySkinDecoder.cs
@@ -30,6 +30,9 @@ namespace osu.Game.Skinning
case @"Author":
skin.SkinInfo.Creator = pair.Value;
break;
+ case @"CursorExpand":
+ skin.CursorExpand = pair.Value != "0";
+ break;
}
break;
diff --git a/osu.Game/Skinning/LocalSkinOverrideContainer.cs b/osu.Game/Skinning/LocalSkinOverrideContainer.cs
index d7d2737d35..2dab671936 100644
--- a/osu.Game/Skinning/LocalSkinOverrideContainer.cs
+++ b/osu.Game/Skinning/LocalSkinOverrideContainer.cs
@@ -43,22 +43,14 @@ namespace osu.Game.Skinning
return fallbackSource?.GetSample(sampleName);
}
- public TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct
+ public TValue GetValue(Func query) where TConfiguration : SkinConfiguration
{
- TValue? val = null;
+ TValue val;
if ((source as Skin)?.Configuration is TConfiguration conf)
- val = query?.Invoke(conf);
+ if (beatmapSkins && (val = query.Invoke(conf)) != null)
+ return val;
- return val ?? fallbackSource?.GetValue(query);
- }
-
- public TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class
- {
- TValue val = null;
- if ((source as Skin)?.Configuration is TConfiguration conf)
- val = query?.Invoke(conf);
-
- return val ?? fallbackSource?.GetValue(query);
+ return fallbackSource == null ? default : fallbackSource.GetValue(query);
}
private readonly ISkinSource source;
diff --git a/osu.Game/Skinning/Skin.cs b/osu.Game/Skinning/Skin.cs
index 29130f45df..21027ff4ab 100644
--- a/osu.Game/Skinning/Skin.cs
+++ b/osu.Game/Skinning/Skin.cs
@@ -22,11 +22,8 @@ namespace osu.Game.Skinning
public abstract Texture GetTexture(string componentName);
- public TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class
- => Configuration is TConfiguration conf ? query?.Invoke(conf) : null;
-
- public TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct
- => Configuration is TConfiguration conf ? query?.Invoke(conf) : null;
+ public TValue GetValue(Func query) where TConfiguration : SkinConfiguration
+ => Configuration is TConfiguration conf ? query.Invoke(conf) : default;
protected Skin(SkinInfo skin)
{
diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs
index 7d354d108c..047be591e2 100644
--- a/osu.Game/Skinning/SkinConfiguration.cs
+++ b/osu.Game/Skinning/SkinConfiguration.cs
@@ -16,5 +16,7 @@ namespace osu.Game.Skinning
public Dictionary CustomColours { get; set; } = new Dictionary();
public string HitCircleFont { get; set; } = "default";
+
+ public bool? CursorExpand { get; set; } = true;
}
}
diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs
index ce179d43ef..454e80d8c6 100644
--- a/osu.Game/Skinning/SkinManager.cs
+++ b/osu.Game/Skinning/SkinManager.cs
@@ -116,8 +116,6 @@ namespace osu.Game.Skinning
public SampleChannel GetSample(string sampleName) => CurrentSkin.Value.GetSample(sampleName);
- public TValue GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : class => CurrentSkin.Value.GetValue(query);
-
- public TValue? GetValue(Func query) where TConfiguration : SkinConfiguration where TValue : struct => CurrentSkin.Value.GetValue(query);
+ public TValue GetValue(Func query) where TConfiguration : SkinConfiguration => CurrentSkin.Value.GetValue(query);
}
}
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
index 8f860c5f53..2330c25443 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardAnimation.cs
@@ -6,7 +6,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Animations;
using osu.Framework.Graphics.Textures;
-using System.Linq;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables
@@ -71,7 +70,7 @@ namespace osu.Game.Storyboards.Drawables
{
var framePath = basePath.Replace(".", frame + ".");
- var path = beatmap.Value.BeatmapSetInfo.Files.FirstOrDefault(f => f.Filename.ToLowerInvariant() == framePath)?.FileInfo.StoragePath;
+ var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.ToLowerInvariant() == framePath)?.FileInfo.StoragePath;
if (path == null)
continue;
diff --git a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs
index 485f9bf61c..b03285b419 100644
--- a/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs
+++ b/osu.Game/Storyboards/Drawables/DrawableStoryboardSprite.cs
@@ -6,7 +6,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
-using System.Linq;
using osu.Game.Beatmaps;
namespace osu.Game.Storyboards.Drawables
@@ -66,7 +65,7 @@ namespace osu.Game.Storyboards.Drawables
private void load(IBindableBeatmap beatmap, TextureStore textureStore)
{
var spritePath = Sprite.Path.ToLowerInvariant();
- var path = beatmap.Value.BeatmapSetInfo.Files.FirstOrDefault(f => f.Filename.ToLowerInvariant() == spritePath)?.FileInfo.StoragePath;
+ var path = beatmap.Value.BeatmapSetInfo.Files.Find(f => f.Filename.ToLowerInvariant() == spritePath)?.FileInfo.StoragePath;
if (path == null)
return;
diff --git a/osu.Game/Users/UserStatistics.cs b/osu.Game/Users/UserStatistics.cs
index f04bfb62bb..8af270454c 100644
--- a/osu.Game/Users/UserStatistics.cs
+++ b/osu.Game/Users/UserStatistics.cs
@@ -78,6 +78,5 @@ namespace osu.Game.Users
[JsonProperty(@"country")]
public int? Country;
}
-
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 103c7c20d6..9365169873 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -15,10 +15,10 @@
-
-
+
+
-
+