diff --git a/.github/ISSUE_TEMPLATE/00-mobile-issues.md b/.github/ISSUE_TEMPLATE/00-mobile-issues.md
deleted file mode 100644
index f171e80b8b..0000000000
--- a/.github/ISSUE_TEMPLATE/00-mobile-issues.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: Mobile Report
-about: ⚠ Due to current development priorities we are not accepting mobile reports at this time (unless you're willing to fix them yourself!)
----
-
-⚠ **PLEASE READ** ⚠: Due to prioritising finishing the client for desktop first we are not accepting reports related to mobile platforms for the time being, unless you're willing to fix them.
-If you'd like to report a problem or suggest a feature and then work on it, feel free to open an issue and highlight that you'd like to address it yourself in the issue body; mobile pull requests are also welcome.
-Otherwise, please check back in the future when the focus of development shifts towards mobile!
diff --git a/.github/ISSUE_TEMPLATE/01-bug-issues.md b/.github/ISSUE_TEMPLATE/01-bug-issues.md
index c8c41e5a78..0b80ce44dd 100644
--- a/.github/ISSUE_TEMPLATE/01-bug-issues.md
+++ b/.github/ISSUE_TEMPLATE/01-bug-issues.md
@@ -8,4 +8,9 @@ about: Issues regarding encountered bugs.
**osu!lazer version:**
-**Logs:**
+**Logs:**
+
diff --git a/.github/ISSUE_TEMPLATE/02-crash-issues.md b/.github/ISSUE_TEMPLATE/02-crash-issues.md
index 8ad27e9e31..ada8de73c0 100644
--- a/.github/ISSUE_TEMPLATE/02-crash-issues.md
+++ b/.github/ISSUE_TEMPLATE/02-crash-issues.md
@@ -8,6 +8,11 @@ about: Issues regarding crashes or permanent freezes.
**osu!lazer version:**
-**Logs:**
+**Logs:**
+
**Computer Specifications:**
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 6480612b2e..4e8af405a2 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -11,11 +11,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -28,11 +23,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -45,11 +35,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Debug)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -62,11 +47,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tests (Release)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tests/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -80,11 +60,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Debug)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -98,11 +73,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build osu! (Release)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Desktop/bin/Release/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -116,11 +86,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tournament tests (Debug)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -134,11 +99,6 @@
],
"cwd": "${workspaceRoot}",
"preLaunchTask": "Build tournament tests (Release)",
- "linux": {
- "env": {
- "LD_LIBRARY_PATH": "${workspaceRoot}/osu.Game.Tournament.Tests/bin/Debug/netcoreapp3.1:${env:LD_LIBRARY_PATH}"
- }
- },
"console": "internalConsole"
},
{
@@ -169,4 +129,4 @@
"externalConsole": false
}
]
-}
\ No newline at end of file
+}
diff --git a/README.md b/README.md
index 6cc110280c..77c7eb9d2d 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the
This project is under heavy development, but is in a stable state. Users are encouraged to try it out and keep it installed alongside the stable *osu!* client. It will continue to evolve to the point of eventually replacing the existing stable client as an update.
-We are accepting bug reports (please report with as much detail as possible). Feature requests are also welcome, but understand that our focus is on completing the game to feature parity before adding new features. A few resources are available as starting points to getting involved and understanding the project:
+We are accepting bug reports (please report with as much detail as possible and follow the existing issue templates). Feature requests are also welcome, but understand that our focus is on completing the game to feature parity before adding new features. A few resources are available as starting points to getting involved and understanding the project:
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
@@ -27,10 +27,9 @@ If you are looking to install or test osu! without setting up a development envi
**Latest build:**
-| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
-| ------------- | ------------- | ------------- | ------------- |
+| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk)
+| ------------- | ------------- | ------------- | ------------- | ------------- |
-- **Linux** users are recommended to self-compile until we have official deployment in place.
- When running on Windows 7 or 8.1, **[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/dependencies?tabs=netcore31&pivots=os-windows)** may be required to correctly run .NET Core applications if your operating system is not up-to-date with the latest service packs.
If your platform is not listed above, there is still a chance you can manually build it by following the instructions below.
diff --git a/osu.Android.props b/osu.Android.props
index b9ef783b2a..1c4a6ffe75 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -25,7 +25,6 @@
portable
False
DEBUG;TRACE
- false
false
true
false
@@ -34,7 +33,6 @@
false
None
True
- true
false
False
true
@@ -53,7 +51,7 @@
-
-
+
+
diff --git a/osu.Android/OsuGameAndroid.cs b/osu.Android/OsuGameAndroid.cs
index a91c010809..84f215f930 100644
--- a/osu.Android/OsuGameAndroid.cs
+++ b/osu.Android/OsuGameAndroid.cs
@@ -30,11 +30,6 @@ namespace osu.Android
}
}
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- Add(new SimpleUpdateManager());
- }
+ protected override UpdateManager CreateUpdateManager() => new SimpleUpdateManager();
}
}
\ No newline at end of file
diff --git a/osu.Android/osu.Android.csproj b/osu.Android/osu.Android.csproj
index ac3905a372..0598a50530 100644
--- a/osu.Android/osu.Android.csproj
+++ b/osu.Android/osu.Android.csproj
@@ -13,6 +13,7 @@
osu.Android
Properties\AndroidManifest.xml
armeabi-v7a;x86;arm64-v8a
+ false
cjk;mideast;other;rare;west
@@ -52,4 +53,4 @@
-
\ No newline at end of file
+
diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs
index f70cc24159..f05ee48914 100644
--- a/osu.Desktop/OsuGameDesktop.cs
+++ b/osu.Desktop/OsuGameDesktop.cs
@@ -47,20 +47,25 @@ namespace osu.Desktop
return null;
}
+ protected override UpdateManager CreateUpdateManager()
+ {
+ switch (RuntimeInfo.OS)
+ {
+ case RuntimeInfo.Platform.Windows:
+ return new SquirrelUpdateManager();
+
+ default:
+ return new SimpleUpdateManager();
+ }
+ }
+
protected override void LoadComplete()
{
base.LoadComplete();
if (!noVersionOverlay)
- {
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue }, Add);
- if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows)
- Add(new SquirrelUpdateManager());
- else
- Add(new SimpleUpdateManager());
- }
-
LoadComponentAsync(new DiscordRichPresence(), Add);
}
diff --git a/osu.Desktop/osu.Desktop.csproj b/osu.Desktop/osu.Desktop.csproj
index b9294088f4..c34e1e1221 100644
--- a/osu.Desktop/osu.Desktop.csproj
+++ b/osu.Desktop/osu.Desktop.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
index 74a9c05bf9..ed7bfb9a44 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneAutoJuiceStream.cs
@@ -7,7 +7,6 @@ using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
using osuTK;
@@ -51,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Tests
return beatmap;
}
- protected override Player CreatePlayer(Ruleset ruleset)
+ protected override TestPlayer CreatePlayer(Ruleset ruleset)
{
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
return base.CreatePlayer(ruleset);
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
index 0ad72412fc..20911b8d06 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
using NUnit.Framework;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Tests.Visual;
@@ -29,6 +29,12 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
+ [Test]
+ public void TestBananaShower()
+ {
+ AddUntilStep("player is done", () => !Player.ValidForResume);
+ }
+
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = new Beatmap
@@ -40,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Tests
}
};
- beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 5000, NewCombo = true });
+ beatmap.HitObjects.Add(new BananaShower { StartTime = 200, Duration = 3000, NewCombo = true });
return beatmap;
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
index 83ea6359c2..df1ac4c725 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
@@ -8,7 +8,10 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
+using osu.Framework.Testing;
using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Tests.Visual;
@@ -30,6 +33,10 @@ namespace osu.Game.Rulesets.Catch.Tests
AddToggleStep("Hyperdash", t =>
CreatedDrawables.OfType().Select(i => i.Child)
.OfType().ForEach(c => c.ToggleHyperDash(t)));
+
+ AddRepeatStep("catch fruit", () =>
+ this.ChildrenOfType().ForEach(area =>
+ area.MovableCatcher.PlaceOnPlate(new DrawableFruit(new TestSceneFruitObjects.TestCatchFruit(FruitVisualRepresentation.Grape)))), 20);
}
private void createCatcher(float size)
@@ -58,6 +65,8 @@ namespace osu.Game.Rulesets.Catch.Tests
{
}
+ public new Catcher MovableCatcher => base.MovableCatcher;
+
public void ToggleHyperDash(bool status) => MovableCatcher.SetHyperDashState(status ? 2 : 1);
}
}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
index 1eb913e900..070847c0c1 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
@@ -10,7 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
index 51c821a1e8..82d5aa936f 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneFruitObjects.cs
@@ -6,8 +6,8 @@ using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
-using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
using osu.Game.Tests.Visual;
using osuTK;
@@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{
typeof(CatchHitObject),
typeof(Fruit),
+ typeof(FruitPiece),
typeof(Droplet),
typeof(Banana),
typeof(BananaShower),
@@ -37,14 +38,59 @@ namespace osu.Game.Rulesets.Catch.Tests
foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
AddStep($"show {rep}", () => SetContents(() => createDrawable(rep)));
+
+ AddStep("show droplet", () => SetContents(createDrawableDroplet));
+
+ AddStep("show tiny droplet", () => SetContents(createDrawableTinyDroplet));
+
+ foreach (FruitVisualRepresentation rep in Enum.GetValues(typeof(FruitVisualRepresentation)))
+ AddStep($"show hyperdash {rep}", () => SetContents(() => createDrawable(rep, true)));
}
- private DrawableFruit createDrawable(FruitVisualRepresentation rep)
+ private Drawable createDrawableTinyDroplet()
+ {
+ var droplet = new TinyDroplet
+ {
+ StartTime = Clock.CurrentTime,
+ Scale = 1.5f,
+ };
+
+ return new DrawableTinyDroplet(droplet)
+ {
+ Anchor = Anchor.Centre,
+ RelativePositionAxes = Axes.None,
+ Position = Vector2.Zero,
+ Alpha = 1,
+ LifetimeStart = double.NegativeInfinity,
+ LifetimeEnd = double.PositiveInfinity,
+ };
+ }
+
+ private Drawable createDrawableDroplet()
+ {
+ var droplet = new Droplet
+ {
+ StartTime = Clock.CurrentTime,
+ Scale = 1.5f,
+ };
+
+ return new DrawableDroplet(droplet)
+ {
+ Anchor = Anchor.Centre,
+ RelativePositionAxes = Axes.None,
+ Position = Vector2.Zero,
+ Alpha = 1,
+ LifetimeStart = double.NegativeInfinity,
+ LifetimeEnd = double.PositiveInfinity,
+ };
+ }
+
+ private Drawable createDrawable(FruitVisualRepresentation rep, bool hyperdash = false)
{
Fruit fruit = new TestCatchFruit(rep)
{
- StartTime = 1000000000000,
Scale = 1.5f,
+ HyperDashTarget = hyperdash ? new Banana() : null
};
return new DrawableFruit(fruit)
@@ -58,11 +104,12 @@ namespace osu.Game.Rulesets.Catch.Tests
};
}
- private class TestCatchFruit : Fruit
+ public class TestCatchFruit : Fruit
{
public TestCatchFruit(FruitVisualRepresentation rep)
{
VisualRepresentation = rep;
+ StartTime = 1000000000000;
}
public override FruitVisualRepresentation VisualRepresentation { get; }
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
new file mode 100644
index 0000000000..cbc87459e1
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneJuiceStream.cs
@@ -0,0 +1,56 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Tests
+{
+ public class TestSceneJuiceStream : PlayerTestScene
+ {
+ public TestSceneJuiceStream()
+ : base(new CatchRuleset())
+ {
+ }
+
+ [Test]
+ public void TestJuiceStreamEndingCombo()
+ {
+ AddUntilStep("player is done", () => !Player.ValidForResume);
+ }
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
+ {
+ BeatmapInfo = new BeatmapInfo
+ {
+ BaseDifficulty = new BeatmapDifficulty { CircleSize = 5, SliderMultiplier = 2 },
+ Ruleset = ruleset
+ },
+ HitObjects = new List
+ {
+ new JuiceStream
+ {
+ X = 0.5f,
+ Path = new SliderPath(PathType.Linear, new[]
+ {
+ Vector2.Zero,
+ new Vector2(0, 100)
+ }),
+ StartTime = 200
+ },
+ new Banana
+ {
+ X = 0.5f,
+ StartTime = 1000,
+ NewCombo = true
+ }
+ }
+ };
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index e5c3647f99..b9d791fdb1 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -21,6 +21,8 @@ using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using System;
+using osu.Game.Rulesets.Catch.Skinning;
+using osu.Game.Skinning;
namespace osu.Game.Rulesets.Catch
{
@@ -141,6 +143,8 @@ namespace osu.Game.Rulesets.Catch
public override DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap) => new CatchDifficultyCalculator(this, beatmap);
+ public override ISkin CreateLegacySkinProvider(ISkinSource source) => new CatchLegacySkinTransformer(source);
+
public override PerformanceCalculator CreatePerformanceCalculator(WorkingBeatmap beatmap, ScoreInfo score) => new CatchPerformanceCalculator(this, beatmap, score);
public int LegacyID => 2;
diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs
index 7e482d4045..02c045f363 100644
--- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs
+++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs
@@ -5,5 +5,11 @@ namespace osu.Game.Rulesets.Catch
{
public enum CatchSkinComponents
{
+ FruitBananas,
+ FruitApple,
+ FruitGrapes,
+ FruitOrange,
+ FruitPear,
+ Droplet
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
index 606a935229..ee88edbea1 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModHidden.cs
@@ -3,7 +3,7 @@
using System.Linq;
using osu.Framework.Graphics;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
diff --git a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
index 0c754412e5..c3488aec11 100644
--- a/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/BananaShower.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Rulesets.Catch.Objects
@@ -11,6 +12,8 @@ namespace osu.Game.Rulesets.Catch.Objects
public override bool LastInCombo => true;
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
+
protected override void CreateNestedHitObjects()
{
base.CreateNestedHitObjects();
diff --git a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
index 5243091625..f3b566f340 100644
--- a/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/CatchHitObject.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Objects
{
public abstract class CatchHitObject : HitObject, IHasXPosition, IHasComboInformation
{
- public const double OBJECT_RADIUS = 44;
+ public const float OBJECT_RADIUS = 64;
private float x;
@@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Catch.Objects
TimePreempt = (float)BeatmapDifficulty.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450);
- Scale = 1.0f - 0.7f * (difficulty.CircleSize - 5) / 5;
+ Scale = (1.0f - 0.7f * (difficulty.CircleSize - 5) / 5) / 2;
}
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
deleted file mode 100644
index 5afdb14888..0000000000
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBanana.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableBanana : DrawableFruit
- {
- public DrawableBanana(Banana h)
- : base(h)
- {
- }
- }
-}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
deleted file mode 100644
index 059310d671..0000000000
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableDroplet.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
-using osuTK;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableDroplet : PalpableCatchHitObject
- {
- private Pulp pulp;
-
- public override bool StaysOnPlate => false;
-
- public DrawableDroplet(Droplet h)
- : base(h)
- {
- Origin = Anchor.Centre;
- Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 4;
- Masking = false;
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- AddInternal(pulp = new Pulp { Size = Size });
-
- AccentColour.BindValueChanged(colour => { pulp.AccentColour = colour.NewValue; }, true);
- }
- }
-}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
deleted file mode 100644
index 53a018c9f4..0000000000
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableFruit.cs
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using osu.Framework.Allocation;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Utils;
-using osu.Game.Rulesets.Catch.Objects.Drawable.Pieces;
-using osuTK;
-using osuTK.Graphics;
-
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
-{
- public class DrawableFruit : PalpableCatchHitObject
- {
- private Circle border;
-
- private const float drawable_radius = (float)CatchHitObject.OBJECT_RADIUS * radius_adjust;
-
- ///
- /// Because we're adding a border around the fruit, we need to scale down some.
- ///
- private const float radius_adjust = 1.1f;
-
- public DrawableFruit(Fruit h)
- : base(h)
- {
- Origin = Anchor.Centre;
-
- Size = new Vector2(drawable_radius);
- Masking = false;
-
- Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- // todo: this should come from the skin.
- AccentColour.Value = colourForRepresentation(HitObject.VisualRepresentation);
-
- AddRangeInternal(new[]
- {
- createPulp(HitObject.VisualRepresentation),
- border = new Circle
- {
- EdgeEffect = new EdgeEffectParameters
- {
- Hollow = !HitObject.HyperDash,
- Type = EdgeEffectType.Glow,
- Radius = 4 * radius_adjust,
- Colour = HitObject.HyperDash ? Color4.Red : AccentColour.Value.Darken(1).Opacity(0.6f)
- },
- Size = new Vector2(Height),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- BorderColour = Color4.White,
- BorderThickness = 3f * radius_adjust,
- Children = new Framework.Graphics.Drawable[]
- {
- new Box
- {
- AlwaysPresent = true,
- Colour = AccentColour.Value,
- Alpha = 0,
- RelativeSizeAxes = Axes.Both
- }
- }
- },
- });
-
- if (HitObject.HyperDash)
- {
- AddInternal(new Pulp
- {
- RelativePositionAxes = Axes.Both,
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- AccentColour = Color4.Red,
- Blending = BlendingParameters.Additive,
- Alpha = 0.5f,
- Scale = new Vector2(1.333f)
- });
- }
- }
-
- private Framework.Graphics.Drawable createPulp(FruitVisualRepresentation representation)
- {
- const float large_pulp_3 = 8f * radius_adjust;
- const float distance_from_centre_3 = 0.15f;
-
- const float large_pulp_4 = large_pulp_3 * 0.925f;
- const float distance_from_centre_4 = distance_from_centre_3 / 0.925f;
-
- const float small_pulp = large_pulp_3 / 2;
-
- static Vector2 positionAt(float angle, float distance) => new Vector2(
- distance * MathF.Sin(angle * MathF.PI / 180),
- distance * MathF.Cos(angle * MathF.PI / 180));
-
- switch (representation)
- {
- default:
- return new Container();
-
- case FruitVisualRepresentation.Raspberry:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(small_pulp),
- Y = -0.34f,
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(0, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(90, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(180, distance_from_centre_4),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_4),
- AccentColour = AccentColour.Value,
- Position = positionAt(270, distance_from_centre_4),
- },
- }
- };
-
- case FruitVisualRepresentation.Pineapple:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(small_pulp),
- Y = -0.3f,
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(45, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(135, distance_from_centre_4),
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4),
- Position = positionAt(225, distance_from_centre_4),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_4),
- AccentColour = AccentColour.Value,
- Position = positionAt(315, distance_from_centre_4),
- },
- }
- };
-
- case FruitVisualRepresentation.Pear:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(small_pulp),
- Y = -0.33f,
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(60, distance_from_centre_3),
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(180, distance_from_centre_3),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_3),
- AccentColour = AccentColour.Value,
- Position = positionAt(300, distance_from_centre_3),
- },
- }
- };
-
- case FruitVisualRepresentation.Grape:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(small_pulp),
- Y = -0.25f,
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(0, distance_from_centre_3),
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_3),
- Position = positionAt(120, distance_from_centre_3),
- },
- new Pulp
- {
- Size = new Vector2(large_pulp_3),
- AccentColour = AccentColour.Value,
- Position = positionAt(240, distance_from_centre_3),
- },
- }
- };
-
- case FruitVisualRepresentation.Banana:
- return new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Framework.Graphics.Drawable[]
- {
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(small_pulp),
- Y = -0.3f
- },
- new Pulp
- {
- AccentColour = AccentColour.Value,
- Size = new Vector2(large_pulp_4 * 0.8f, large_pulp_4 * 2.5f),
- Y = 0.05f,
- },
- }
- };
- }
- }
-
- protected override void Update()
- {
- base.Update();
-
- border.Alpha = (float)Math.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
- }
-
- private Color4 colourForRepresentation(FruitVisualRepresentation representation)
- {
- switch (representation)
- {
- default:
- case FruitVisualRepresentation.Pear:
- return new Color4(17, 136, 170, 255);
-
- case FruitVisualRepresentation.Grape:
- return new Color4(204, 102, 0, 255);
-
- case FruitVisualRepresentation.Raspberry:
- return new Color4(121, 9, 13, 255);
-
- case FruitVisualRepresentation.Pineapple:
- return new Color4(102, 136, 0, 255);
-
- case FruitVisualRepresentation.Banana:
- switch (RNG.Next(0, 3))
- {
- default:
- return new Color4(255, 240, 0, 255);
-
- case 1:
- return new Color4(255, 192, 0, 255);
-
- case 2:
- return new Color4(214, 221, 28, 255);
- }
- }
- }
- }
-}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/BananaPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/BananaPiece.cs
new file mode 100644
index 0000000000..ebb0bf0f2c
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/BananaPiece.cs
@@ -0,0 +1,31 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class BananaPiece : PulpFormation
+ {
+ public BananaPiece()
+ {
+ InternalChildren = new Drawable[]
+ {
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(SMALL_PULP),
+ Y = -0.3f
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4 * 0.8f, LARGE_PULP_4 * 2.5f),
+ Y = 0.05f,
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
new file mode 100644
index 0000000000..cf7231ebb2
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
@@ -0,0 +1,40 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Utils;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class DrawableBanana : DrawableFruit
+ {
+ public DrawableBanana(Banana h)
+ : base(h)
+ {
+ }
+
+ private Color4? colour;
+
+ protected override Color4 GetComboColour(IReadOnlyList comboColours)
+ {
+ // override any external colour changes with banananana
+ return colour ??= getBananaColour();
+ }
+
+ private Color4 getBananaColour()
+ {
+ switch (RNG.Next(0, 3))
+ {
+ default:
+ return new Color4(255, 240, 0, 255);
+
+ case 1:
+ return new Color4(255, 192, 0, 255);
+
+ case 2:
+ return new Color4(214, 221, 28, 255);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs
similarity index 97%
rename from osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
rename to osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs
index ea415e18fa..4ce80aceb8 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableBananaShower.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBananaShower.cs
@@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public class DrawableBananaShower : DrawableCatchHitObject
{
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
similarity index 70%
rename from osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
rename to osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
index b7c05392f3..5bfe0515a1 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
@@ -2,24 +2,51 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using osuTK;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
+using osuTK;
+using osuTK.Graphics;
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public abstract class PalpableCatchHitObject : DrawableCatchHitObject
where TObject : CatchHitObject
{
public override bool CanBePlated => true;
+ protected Container ScaleContainer { get; private set; }
+
protected PalpableCatchHitObject(TObject hitObject)
: base(hitObject)
{
- Scale = new Vector2(HitObject.Scale);
+ Origin = Anchor.Centre;
+ Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
+ Masking = false;
}
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ AddRangeInternal(new Drawable[]
+ {
+ ScaleContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ }
+ });
+
+ ScaleContainer.Scale = new Vector2(HitObject.Scale);
+ }
+
+ protected override Color4 GetComboColour(IReadOnlyList comboColours) =>
+ comboColours[(HitObject.IndexInBeatmap + 1) % comboColours.Count];
}
public abstract class DrawableCatchHitObject : DrawableCatchHitObject
@@ -41,6 +68,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
public virtual bool StaysOnPlate => CanBePlated;
+ public float DisplayRadius => DrawSize.X / 2 * Scale.X * HitObject.Scale;
+
protected DrawableCatchHitObject(CatchHitObject hitObject)
: base(hitObject)
{
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
new file mode 100644
index 0000000000..0a8e830af9
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
@@ -0,0 +1,42 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Utils;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
+using osu.Game.Skinning;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class DrawableDroplet : PalpableCatchHitObject
+ {
+ public override bool StaysOnPlate => false;
+
+ public DrawableDroplet(Droplet h)
+ : base(h)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ScaleContainer.Child = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.Droplet), _ => new Pulp
+ {
+ Size = Size / 4,
+ AccentColour = { BindTarget = AccentColour }
+ });
+ }
+
+ protected override void UpdateInitialTransforms()
+ {
+ base.UpdateInitialTransforms();
+
+ // roughly matches osu-stable
+ float startRotation = RNG.NextSingle() * 20;
+ double duration = HitObject.TimePreempt + 2000;
+
+ this.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
new file mode 100644
index 0000000000..197ad41247
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
@@ -0,0 +1,50 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Utils;
+using osu.Game.Skinning;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class DrawableFruit : PalpableCatchHitObject
+ {
+ public DrawableFruit(Fruit h)
+ : base(h)
+ {
+ Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ScaleContainer.Child = new SkinnableDrawable(
+ new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece());
+ }
+
+ private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation)
+ {
+ switch (hitObjectVisualRepresentation)
+ {
+ case FruitVisualRepresentation.Pear:
+ return CatchSkinComponents.FruitPear;
+
+ case FruitVisualRepresentation.Grape:
+ return CatchSkinComponents.FruitGrapes;
+
+ case FruitVisualRepresentation.Pineapple:
+ return CatchSkinComponents.FruitApple;
+
+ case FruitVisualRepresentation.Raspberry:
+ return CatchSkinComponents.FruitOrange;
+
+ case FruitVisualRepresentation.Banana:
+ return CatchSkinComponents.FruitBananas;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(hitObjectVisualRepresentation), hitObjectVisualRepresentation, null);
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
similarity index 87%
rename from osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
rename to osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
index a24821b3ce..932464cfd1 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
@@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public class DrawableJuiceStream : DrawableCatchHitObject
{
@@ -42,10 +42,11 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
switch (hitObject)
{
case CatchHitObject catchObject:
- return createDrawableRepresentation?.Invoke(catchObject)?.With(o => ((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
+ return createDrawableRepresentation?.Invoke(catchObject)?.With(o =>
+ ((DrawableCatchHitObject)o).CheckPosition = p => CheckPosition?.Invoke(p) ?? false);
}
- return base.CreateNestedHitObject(hitObject);
+ throw new ArgumentException($"{nameof(hitObject)} must be of type {nameof(CatchHitObject)}.");
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs
similarity index 60%
rename from osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
rename to osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs
index d41aea1e7b..ae775684d8 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/DrawableTinyDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableTinyDroplet.cs
@@ -1,16 +1,21 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osuTK;
+using osu.Framework.Allocation;
-namespace osu.Game.Rulesets.Catch.Objects.Drawable
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
public class DrawableTinyDroplet : DrawableDroplet
{
public DrawableTinyDroplet(TinyDroplet h)
: base(h)
{
- Size = new Vector2((float)CatchHitObject.OBJECT_RADIUS) / 8;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ScaleContainer.Scale /= 2;
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/FruitPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/FruitPiece.cs
new file mode 100644
index 0000000000..5797588ded
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/FruitPiece.cs
@@ -0,0 +1,116 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Rulesets.Objects.Drawables;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ internal class FruitPiece : CompositeDrawable
+ {
+ ///
+ /// Because we're adding a border around the fruit, we need to scale down some.
+ ///
+ public const float RADIUS_ADJUST = 1.1f;
+
+ private Circle border;
+
+ private CatchHitObject hitObject;
+
+ private readonly IBindable accentColour = new Bindable();
+
+ public FruitPiece()
+ {
+ RelativeSizeAxes = Axes.Both;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(DrawableHitObject drawableObject)
+ {
+ DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
+ hitObject = drawableCatchObject.HitObject;
+
+ accentColour.BindTo(drawableCatchObject.AccentColour);
+
+ AddRangeInternal(new[]
+ {
+ getFruitFor(drawableCatchObject.HitObject.VisualRepresentation),
+ border = new Circle
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ BorderColour = Color4.White,
+ BorderThickness = 6f * RADIUS_ADJUST,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ AlwaysPresent = true,
+ Alpha = 0,
+ RelativeSizeAxes = Axes.Both
+ }
+ }
+ },
+ });
+
+ if (hitObject.HyperDash)
+ {
+ AddInternal(new Circle
+ {
+ RelativeSizeAxes = Axes.Both,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ BorderColour = Color4.Red,
+ BorderThickness = 12f * RADIUS_ADJUST,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ AlwaysPresent = true,
+ Alpha = 0.3f,
+ Blending = BlendingParameters.Additive,
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Red,
+ }
+ }
+ });
+ }
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+ border.Alpha = (float)Math.Clamp((hitObject.StartTime - Time.Current) / 500, 0, 1);
+ }
+
+ private Drawable getFruitFor(FruitVisualRepresentation representation)
+ {
+ switch (representation)
+ {
+ case FruitVisualRepresentation.Pear:
+ return new PearPiece();
+
+ case FruitVisualRepresentation.Grape:
+ return new GrapePiece();
+
+ case FruitVisualRepresentation.Pineapple:
+ return new PineapplePiece();
+
+ case FruitVisualRepresentation.Banana:
+ return new BananaPiece();
+
+ case FruitVisualRepresentation.Raspberry:
+ return new RaspberryPiece();
+ }
+
+ return Empty();
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/GrapePiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/GrapePiece.cs
new file mode 100644
index 0000000000..1d1faf893b
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/GrapePiece.cs
@@ -0,0 +1,43 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class GrapePiece : PulpFormation
+ {
+ public GrapePiece()
+ {
+ InternalChildren = new Drawable[]
+ {
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(SMALL_PULP),
+ Y = -0.25f,
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_3),
+ Position = PositionAt(0, DISTANCE_FROM_CENTRE_3),
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_3),
+ Position = PositionAt(120, DISTANCE_FROM_CENTRE_3),
+ },
+ new Pulp
+ {
+ Size = new Vector2(LARGE_PULP_3),
+ AccentColour = { BindTarget = AccentColour },
+ Position = PositionAt(240, DISTANCE_FROM_CENTRE_3),
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/PearPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/PearPiece.cs
new file mode 100644
index 0000000000..7f14217cda
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/PearPiece.cs
@@ -0,0 +1,43 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class PearPiece : PulpFormation
+ {
+ public PearPiece()
+ {
+ InternalChildren = new Drawable[]
+ {
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(SMALL_PULP),
+ Y = -0.33f,
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_3),
+ Position = PositionAt(60, DISTANCE_FROM_CENTRE_3),
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_3),
+ Position = PositionAt(180, DISTANCE_FROM_CENTRE_3),
+ },
+ new Pulp
+ {
+ Size = new Vector2(LARGE_PULP_3),
+ AccentColour = { BindTarget = AccentColour },
+ Position = PositionAt(300, DISTANCE_FROM_CENTRE_3),
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/Pulp.cs
similarity index 62%
rename from osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
rename to osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/Pulp.cs
index 1e9daf18db..1e7506a257 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawable/Pieces/Pulp.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/Pieces/Pulp.cs
@@ -1,16 +1,16 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
using osuTK.Graphics;
-namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
+namespace osu.Game.Rulesets.Catch.Objects.Drawables.Pieces
{
- public class Pulp : Circle, IHasAccentColour
+ public class Pulp : Circle
{
public Pulp()
{
@@ -22,32 +22,23 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
Colour = Color4.White.Opacity(0.9f);
}
- private Color4 accentColour;
+ public readonly Bindable AccentColour = new Bindable();
- public Color4 AccentColour
+ protected override void LoadComplete()
{
- get => accentColour;
- set
- {
- accentColour = value;
- if (IsLoaded) updateAccentColour();
- }
+ base.LoadComplete();
+
+ AccentColour.BindValueChanged(updateAccentColour, true);
}
- private void updateAccentColour()
+ private void updateAccentColour(ValueChangedEvent colour)
{
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
Radius = Size.X / 2,
- Colour = accentColour.Darken(0.2f).Opacity(0.75f)
+ Colour = colour.NewValue.Darken(0.2f).Opacity(0.75f)
};
}
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- updateAccentColour();
- }
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/PineapplePiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/PineapplePiece.cs
new file mode 100644
index 0000000000..c328ba1837
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/PineapplePiece.cs
@@ -0,0 +1,49 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class PineapplePiece : PulpFormation
+ {
+ public PineapplePiece()
+ {
+ InternalChildren = new Drawable[]
+ {
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(SMALL_PULP),
+ Y = -0.3f,
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4),
+ Position = PositionAt(45, DISTANCE_FROM_CENTRE_4),
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4),
+ Position = PositionAt(135, DISTANCE_FROM_CENTRE_4),
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4),
+ Position = PositionAt(225, DISTANCE_FROM_CENTRE_4),
+ },
+ new Pulp
+ {
+ Size = new Vector2(LARGE_PULP_4),
+ AccentColour = { BindTarget = AccentColour },
+ Position = PositionAt(315, DISTANCE_FROM_CENTRE_4),
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/PulpFormation.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/PulpFormation.cs
new file mode 100644
index 0000000000..be70c3400c
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/PulpFormation.cs
@@ -0,0 +1,43 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Objects.Drawables;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public abstract class PulpFormation : CompositeDrawable
+ {
+ protected readonly IBindable AccentColour = new Bindable();
+
+ protected const float LARGE_PULP_3 = 16f * FruitPiece.RADIUS_ADJUST;
+ protected const float DISTANCE_FROM_CENTRE_3 = 0.15f;
+
+ protected const float LARGE_PULP_4 = LARGE_PULP_3 * 0.925f;
+ protected const float DISTANCE_FROM_CENTRE_4 = DISTANCE_FROM_CENTRE_3 / 0.925f;
+
+ protected const float SMALL_PULP = LARGE_PULP_3 / 2;
+
+ protected PulpFormation()
+ {
+ RelativeSizeAxes = Axes.Both;
+ }
+
+ protected static Vector2 PositionAt(float angle, float distance) => new Vector2(
+ distance * MathF.Sin(angle * MathF.PI / 180),
+ distance * MathF.Cos(angle * MathF.PI / 180));
+
+ [BackgroundDependencyLoader]
+ private void load(DrawableHitObject drawableObject)
+ {
+ DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
+ AccentColour.BindTo(drawableCatchObject.AccentColour);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/RaspberryPiece.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/RaspberryPiece.cs
new file mode 100644
index 0000000000..22ce3ba5b3
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/RaspberryPiece.cs
@@ -0,0 +1,49 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Rulesets.Catch.Objects.Drawables.Pieces;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Objects.Drawables
+{
+ public class RaspberryPiece : PulpFormation
+ {
+ public RaspberryPiece()
+ {
+ InternalChildren = new Drawable[]
+ {
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(SMALL_PULP),
+ Y = -0.34f,
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4),
+ Position = PositionAt(0, DISTANCE_FROM_CENTRE_4),
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4),
+ Position = PositionAt(90, DISTANCE_FROM_CENTRE_4),
+ },
+ new Pulp
+ {
+ AccentColour = { BindTarget = AccentColour },
+ Size = new Vector2(LARGE_PULP_4),
+ Position = PositionAt(180, DISTANCE_FROM_CENTRE_4),
+ },
+ new Pulp
+ {
+ Size = new Vector2(LARGE_PULP_4),
+ AccentColour = { BindTarget = AccentColour },
+ Position = PositionAt(270, DISTANCE_FROM_CENTRE_4),
+ },
+ };
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index 11e2466275..642ff0246e 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -7,6 +7,7 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
@@ -19,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects
///
private const float base_scoring_distance = 100;
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
+
public int RepeatCount { get; set; }
public double Velocity;
diff --git a/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs
new file mode 100644
index 0000000000..36164c5543
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Skinning/CatchLegacySkinTransformer.cs
@@ -0,0 +1,58 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using Humanizer;
+using osu.Framework.Audio.Sample;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Textures;
+using osu.Game.Audio;
+using osu.Game.Skinning;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Skinning
+{
+ public class CatchLegacySkinTransformer : ISkin
+ {
+ private readonly ISkin source;
+
+ public CatchLegacySkinTransformer(ISkinSource source)
+ {
+ this.source = source;
+ }
+
+ public Drawable GetDrawableComponent(ISkinComponent component)
+ {
+ if (!(component is CatchSkinComponent catchSkinComponent))
+ return null;
+
+ switch (catchSkinComponent.Component)
+ {
+ case CatchSkinComponents.FruitApple:
+ case CatchSkinComponents.FruitBananas:
+ case CatchSkinComponents.FruitOrange:
+ case CatchSkinComponents.FruitGrapes:
+ case CatchSkinComponents.FruitPear:
+ var lookupName = catchSkinComponent.Component.ToString().Kebaberize();
+ if (GetTexture(lookupName) != null)
+ return new LegacyFruitPiece(lookupName);
+
+ break;
+
+ case CatchSkinComponents.Droplet:
+ if (GetTexture("fruit-drop") != null)
+ return new LegacyFruitPiece("fruit-drop") { Scale = new Vector2(0.8f) };
+
+ break;
+ }
+
+ return null;
+ }
+
+ public Texture GetTexture(string componentName) => source.GetTexture(componentName);
+
+ public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
+
+ public IBindable GetConfig(TLookup lookup) => source.GetConfig(lookup);
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs b/osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs
new file mode 100644
index 0000000000..25ee0811d0
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Skinning/LegacyFruitPiece.cs
@@ -0,0 +1,79 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Skinning;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Catch.Skinning
+{
+ internal class LegacyFruitPiece : CompositeDrawable
+ {
+ private readonly string lookupName;
+
+ private readonly IBindable accentColour = new Bindable();
+ private Sprite colouredSprite;
+
+ public LegacyFruitPiece(string lookupName)
+ {
+ this.lookupName = lookupName;
+ RelativeSizeAxes = Axes.Both;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(DrawableHitObject drawableObject, ISkinSource skin)
+ {
+ DrawableCatchHitObject drawableCatchObject = (DrawableCatchHitObject)drawableObject;
+
+ accentColour.BindTo(drawableCatchObject.AccentColour);
+
+ InternalChildren = new Drawable[]
+ {
+ colouredSprite = new Sprite
+ {
+ Texture = skin.GetTexture(lookupName),
+ Colour = drawableObject.AccentColour.Value,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ new Sprite
+ {
+ Texture = skin.GetTexture($"{lookupName}-overlay"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ };
+
+ if (drawableCatchObject.HitObject.HyperDash)
+ {
+ var hyperDash = new Sprite
+ {
+ Texture = skin.GetTexture(lookupName),
+ Colour = Color4.Red,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Blending = BlendingParameters.Additive,
+ Depth = 1,
+ Alpha = 0.7f,
+ Scale = new Vector2(1.2f)
+ };
+
+ AddInternal(hyperDash);
+ }
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ accentColour.BindValueChanged(colour => colouredSprite.Colour = colour.NewValue, true);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
index 2d71fb93fb..2319c5ac1f 100644
--- a/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatchPlayfield.cs
@@ -6,7 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.UI.Scrolling;
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 1ad12dc4ad..b977d46611 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -4,14 +4,16 @@
using System;
using System.Linq;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
using osu.Framework.Input.Bindings;
using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
@@ -48,6 +50,9 @@ namespace osu.Game.Rulesets.Catch.UI
public void OnResult(DrawableCatchHitObject fruit, JudgementResult result)
{
+ if (result.Judgement is IgnoreJudgement)
+ return;
+
void runAfterLoaded(Action action)
{
if (lastPlateableFruit == null)
@@ -74,11 +79,11 @@ namespace osu.Game.Rulesets.Catch.UI
caughtFruit.Anchor = Anchor.TopCentre;
caughtFruit.Origin = Anchor.Centre;
- caughtFruit.Scale *= 0.7f;
+ caughtFruit.Scale *= 0.5f;
caughtFruit.LifetimeStart = caughtFruit.HitObject.StartTime;
caughtFruit.LifetimeEnd = double.MaxValue;
- MovableCatcher.Add(caughtFruit);
+ MovableCatcher.PlaceOnPlate(caughtFruit);
lastPlateableFruit = caughtFruit;
if (!fruit.StaysOnPlate)
@@ -87,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (fruit.HitObject.LastInCombo)
{
- if (((CatchJudgement)result.Judgement).ShouldExplodeFor(result))
+ if (result.Judgement is CatchJudgement catchJudgement && catchJudgement.ShouldExplodeFor(result))
runAfterLoaded(() => MovableCatcher.Explode());
else
MovableCatcher.Drop();
@@ -221,9 +226,9 @@ namespace osu.Game.Rulesets.Catch.UI
/// Add a caught fruit to the catcher's stack.
///
/// The fruit that was caught.
- public void Add(DrawableHitObject fruit)
+ public void PlaceOnPlate(DrawableCatchHitObject fruit)
{
- float ourRadius = fruit.DrawSize.X / 2 * fruit.Scale.X;
+ float ourRadius = fruit.DisplayRadius;
float theirRadius = 0;
const float allowance = 6;
@@ -240,6 +245,12 @@ namespace osu.Game.Rulesets.Catch.UI
fruit.X = Math.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2);
caughtFruit.Add(fruit);
+
+ Add(new HitExplosion(fruit)
+ {
+ X = fruit.X,
+ Scale = new Vector2(fruit.HitObject.Scale)
+ });
}
///
@@ -465,4 +476,112 @@ namespace osu.Game.Rulesets.Catch.UI
}
}
}
+
+ public class HitExplosion : CompositeDrawable
+ {
+ private readonly CircularContainer largeFaint;
+
+ public HitExplosion(DrawableCatchHitObject fruit)
+ {
+ Size = new Vector2(20);
+ Anchor = Anchor.TopCentre;
+ Origin = Anchor.BottomCentre;
+
+ Color4 objectColour = fruit.AccentColour.Value;
+
+ // scale roughly in-line with visual appearance of notes
+
+ const float angle_variangle = 15; // should be less than 45
+
+ const float roundness = 100;
+
+ const float initial_height = 10;
+
+ var colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1);
+
+ InternalChildren = new Drawable[]
+ {
+ largeFaint = new CircularContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ // we want our size to be very small so the glow dominates it.
+ Size = new Vector2(0.8f),
+ Blending = BlendingParameters.Additive,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f),
+ Roundness = 160,
+ Radius = 200,
+ },
+ },
+ new CircularContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ Blending = BlendingParameters.Additive,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1),
+ Roundness = 20,
+ Radius = 50,
+ },
+ },
+ new CircularContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ Size = new Vector2(0.01f, initial_height),
+ Blending = BlendingParameters.Additive,
+ Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = colour,
+ Roundness = roundness,
+ Radius = 40,
+ },
+ },
+ new CircularContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ Size = new Vector2(0.01f, initial_height),
+ Blending = BlendingParameters.Additive,
+ Rotation = RNG.NextSingle(-angle_variangle, angle_variangle),
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Colour = colour,
+ Roundness = roundness,
+ Radius = 40,
+ },
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ const double duration = 400;
+
+ largeFaint
+ .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint)
+ .FadeOut(duration * 2);
+
+ this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out);
+ Expire(true);
+ }
+ }
}
diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
index fdd820b891..fd8a1d175d 100644
--- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs
@@ -8,7 +8,7 @@ using osu.Game.Configuration;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
using osu.Game.Rulesets.Catch.Objects;
-using osu.Game.Rulesets.Catch.Objects.Drawable;
+using osu.Game.Rulesets.Catch.Objects.Drawables;
using osu.Game.Rulesets.Catch.Replays;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
diff --git a/osu.Game.Rulesets.Mania.Tests/SkinnableTestScene.cs b/osu.Game.Rulesets.Mania.Tests/SkinnableTestScene.cs
deleted file mode 100644
index 80b1b3df8e..0000000000
--- a/osu.Game.Rulesets.Mania.Tests/SkinnableTestScene.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using osu.Framework.Allocation;
-using osu.Framework.Audio;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Skinning;
-using osu.Game.Tests.Visual;
-
-namespace osu.Game.Rulesets.Mania.Tests
-{
- public abstract class SkinnableTestScene : OsuGridTestScene
- {
- private Skin defaultSkin;
-
- protected SkinnableTestScene()
- : base(1, 2)
- {
- }
-
- [BackgroundDependencyLoader]
- private void load(AudioManager audio, SkinManager skinManager)
- {
- defaultSkin = skinManager.GetSkin(DefaultLegacySkin.Info);
- }
-
- public void SetContents(Func creationFunction)
- {
- Cell(0).Child = createProvider(null, creationFunction);
- Cell(1).Child = createProvider(defaultSkin, creationFunction);
- }
-
- private Drawable createProvider(Skin skin, Func creationFunction)
- {
- var mainProvider = new SkinProvidingContainer(skin);
-
- return mainProvider
- .WithChild(new SkinProvidingContainer(Ruleset.Value.CreateInstance().CreateLegacySkinProvider(mainProvider))
- {
- Child = creationFunction()
- });
- }
- }
-}
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableJudgement.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableJudgement.cs
index eea1a36a19..692d079c16 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableJudgement.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneDrawableJudgement.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
+using osu.Game.Tests.Visual;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
diff --git a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs b/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
deleted file mode 100644
index e8b48768a1..0000000000
--- a/osu.Game.Rulesets.Mania/Judgements/HoldNoteJudgement.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Game.Rulesets.Scoring;
-
-namespace osu.Game.Rulesets.Mania.Judgements
-{
- public class HoldNoteJudgement : ManiaJudgement
- {
- public override bool AffectsCombo => false;
-
- protected override int NumericResultFor(HitResult result) => 0;
- }
-}
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
index 6893e1e73b..86a00271e9 100644
--- a/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModFlashlight.cs
@@ -3,8 +3,8 @@
using System;
using osu.Framework.Bindables;
-using osu.Framework.Caching;
using osu.Framework.Graphics;
+using osu.Framework.Layout;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
using osuTK;
@@ -22,21 +22,13 @@ namespace osu.Game.Rulesets.Mania.Mods
private class ManiaFlashlight : Flashlight
{
- private readonly Cached flashlightProperties = new Cached();
+ private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
public ManiaFlashlight()
{
FlashlightSize = new Vector2(0, default_flashlight_size);
- }
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & Invalidation.DrawSize) > 0)
- {
- flashlightProperties.Invalidate();
- }
-
- return base.Invalidate(invalidation, source, shallPropagate);
+ AddLayout(flashlightProperties);
}
protected override void Update()
diff --git a/osu.Game.Rulesets.Mania/Objects/BarLine.cs b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
index 0981b028b2..09a746042b 100644
--- a/osu.Game.Rulesets.Mania/Objects/BarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/BarLine.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mania.Objects
@@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Mania.Objects
public class BarLine : ManiaHitObject, IBarLine
{
public bool Major { get; set; }
+
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
index 56bc797c7f..08b5b75f9c 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableBarLine.cs
@@ -71,8 +71,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{
}
- protected override void UpdateStateTransforms(ArmedState state)
- {
- }
+ protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
}
}
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
index 31a4857805..43f9ae2783 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/Pieces/BodyPiece.cs
@@ -2,13 +2,13 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using osu.Framework.Caching;
using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Layout;
using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
@@ -65,6 +65,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
}
}
};
+
+ AddLayout(subtractionCache);
}
protected override void LoadComplete()
@@ -100,15 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
}
}
- private readonly Cached subtractionCache = new Cached();
-
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & Invalidation.DrawSize) > 0)
- subtractionCache.Invalidate();
-
- return base.Invalidate(invalidation, source, shallPropagate);
- }
+ private readonly LayoutValue subtractionCache = new LayoutValue(Invalidation.DrawSize);
protected override void Update()
{
diff --git a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
index 86d3d2b2b0..049bf55f90 100644
--- a/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/HoldNote.cs
@@ -4,7 +4,6 @@
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Scoring;
@@ -103,7 +102,7 @@ namespace osu.Game.Rulesets.Mania.Objects
}
}
- public override Judgement CreateJudgement() => new HoldNoteJudgement();
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
diff --git a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
index a28de7ea58..bfe9f1085b 100644
--- a/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
+++ b/osu.Game.Rulesets.Mania/UI/ManiaStage.cs
@@ -115,9 +115,8 @@ namespace osu.Game.Rulesets.Mania.UI
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
- AutoSizeAxes = Axes.Both,
+ RelativeSizeAxes = Axes.Both,
Y = HIT_TARGET_POSITION + 150,
- BypassAutoSizeAxes = Axes.Both
},
topLevelContainer = new Container { RelativeSizeAxes = Axes.Both }
}
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs
new file mode 100644
index 0000000000..69415b70e3
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModDifficultyAdjust.cs
@@ -0,0 +1,86 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Testing;
+using osu.Framework.Utils;
+using osu.Game.Graphics.Containers;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Osu.Tests.Mods
+{
+ public class TestSceneOsuModDifficultyAdjust : ModTestScene
+ {
+ public TestSceneOsuModDifficultyAdjust()
+ : base(new OsuRuleset())
+ {
+ }
+
+ [Test]
+ public void TestNoAdjustment() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModDifficultyAdjust(),
+ Autoplay = true,
+ PassCondition = checkSomeHit
+ });
+
+ [Test]
+ public void TestCircleSize1() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModDifficultyAdjust { CircleSize = { Value = 1 } },
+ Autoplay = true,
+ PassCondition = () => checkSomeHit() && checkObjectsScale(0.78f)
+ });
+
+ [Test]
+ public void TestCircleSize10() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModDifficultyAdjust { CircleSize = { Value = 10 } },
+ Autoplay = true,
+ PassCondition = () => checkSomeHit() && checkObjectsScale(0.15f)
+ });
+
+ [Test]
+ public void TestApproachRate1() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModDifficultyAdjust { ApproachRate = { Value = 1 } },
+ Autoplay = true,
+ PassCondition = () => checkSomeHit() && checkObjectsPreempt(1680)
+ });
+
+ [Test]
+ public void TestApproachRate10() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModDifficultyAdjust { ApproachRate = { Value = 10 } },
+ Autoplay = true,
+ PassCondition = () => checkSomeHit() && checkObjectsPreempt(450)
+ });
+
+ private bool checkObjectsPreempt(double target)
+ {
+ var objects = Player.ChildrenOfType();
+ if (!objects.Any())
+ return false;
+
+ return objects.All(o => o.HitObject.TimePreempt == target);
+ }
+
+ private bool checkObjectsScale(float target)
+ {
+ var objects = Player.ChildrenOfType();
+ if (!objects.Any())
+ return false;
+
+ return objects.All(o => Precision.AlmostEquals(o.ChildrenOfType().First().Children.OfType().Single().Scale.X, target));
+ }
+
+ private bool checkSomeHit()
+ {
+ return Player.ScoreProcessor.JudgedHits >= 2;
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
index 94ca2d4cd1..87da7ef417 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneFollowPoints.cs
@@ -2,9 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Testing;
+using osu.Framework.Utils;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects;
@@ -114,6 +117,22 @@ namespace osu.Game.Rulesets.Osu.Tests
assertGroups();
}
+ [Test]
+ public void TestStackedObjects()
+ {
+ addObjectsStep(() => new OsuHitObject[]
+ {
+ new HitCircle { Position = new Vector2(300, 100) },
+ new HitCircle
+ {
+ Position = new Vector2(300, 300),
+ StackHeight = 20
+ },
+ });
+
+ assertDirections();
+ }
+
private void addMultipleObjectsStep() => addObjectsStep(() => new OsuHitObject[]
{
new HitCircle { Position = new Vector2(100, 100) },
@@ -207,6 +226,33 @@ namespace osu.Game.Rulesets.Osu.Tests
});
}
+ private void assertDirections()
+ {
+ AddAssert("group directions are correct", () =>
+ {
+ for (int i = 0; i < hitObjectContainer.Count; i++)
+ {
+ DrawableOsuHitObject expectedStart = getObject(i);
+ DrawableOsuHitObject expectedEnd = i < hitObjectContainer.Count - 1 ? getObject(i + 1) : null;
+
+ if (expectedEnd == null)
+ continue;
+
+ var points = getGroup(i).ChildrenOfType().ToArray();
+ if (points.Length == 0)
+ continue;
+
+ float expectedDirection = MathF.Atan2(expectedStart.Position.Y - expectedEnd.Position.Y, expectedStart.Position.X - expectedEnd.Position.X);
+ float realDirection = MathF.Atan2(expectedStart.Position.Y - points[^1].Position.Y, expectedStart.Position.X - points[^1].Position.X);
+
+ if (!Precision.AlmostEquals(expectedDirection, realDirection))
+ throw new AssertionException($"Expected group {i} in direction {expectedDirection}, but was {realDirection}.");
+ }
+
+ return true;
+ });
+ }
+
private DrawableOsuHitObject getObject(int index) => hitObjectContainer[index];
private FollowPointConnection getGroup(int index) => followPointRenderer.Connections[index];
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs
index 412effe176..19736a7709 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuFlashlight.cs
@@ -3,13 +3,13 @@
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
-using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneOsuFlashlight : TestSceneOsuPlayer
{
- protected override Player CreatePlayer(Ruleset ruleset)
+ protected override TestPlayer CreatePlayer(Ruleset ruleset)
{
SelectedMods.Value = new Mod[] { new OsuModAutoplay(), new OsuModFlashlight(), };
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
index 4da1b1dae0..d39e24fc1f 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSkinFallbacks.cs
@@ -18,7 +18,6 @@ using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu.Objects.Drawables;
-using osu.Game.Screens.Play;
using osu.Game.Skinning;
using osu.Game.Storyboards;
using osu.Game.Tests.Visual;
@@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNextHitObject(string skin) =>
AddUntilStep($"check skin from {skin}", () =>
{
- var firstObject = ((TestPlayer)Player).DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.OfType().FirstOrDefault();
+ var firstObject = Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.OfType().FirstOrDefault();
if (firstObject == null)
return false;
@@ -75,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Tests
[Resolved]
private AudioManager audio { get; set; }
- protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
+ protected override TestPlayer CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, audio, testBeatmapSkin);
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
index 5cf571d961..ea006ec607 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinnerRotation.cs
@@ -11,7 +11,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
-using osu.Game.Tests.Visual;
using osuTK;
using System.Collections.Generic;
using System.Linq;
@@ -44,7 +43,7 @@ namespace osu.Game.Rulesets.Osu.Tests
base.SetUpSteps();
AddUntilStep("wait for track to start running", () => track.IsRunning);
- AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)((TestPlayer)Player).DrawableRuleset.Playfield.AllHitObjects.First());
+ AddStep("retrieve spinner", () => drawableSpinner = (DrawableSpinner)Player.DrawableRuleset.Playfield.AllHitObjects.First());
}
[Test]
@@ -89,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
AddStep($"seek to {time}", () => track.Seek(time));
- AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, ((TestPlayer)Player).DrawableRuleset.FrameStableClock.CurrentTime, 100));
+ AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
}
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
diff --git a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs b/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
deleted file mode 100644
index 5104d9494b..0000000000
--- a/osu.Game.Rulesets.Osu/Judgements/OsuSliderTailJudgement.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Game.Rulesets.Scoring;
-
-namespace osu.Game.Rulesets.Osu.Judgements
-{
- public class OsuSliderTailJudgement : OsuJudgement
- {
- public override bool AffectsCombo => false;
-
- protected override int NumericResultFor(HitResult result) => 0;
- }
-}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
index a5e89210f6..3e9c0f341b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointConnection.cs
@@ -20,6 +20,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
private const int spacing = 32;
private const double preempt = 800;
+ public override bool RemoveWhenNotAlive => false;
+
///
/// The start time of .
///
@@ -79,27 +81,31 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
drawableObject.HitObject.DefaultsApplied += scheduleRefresh;
}
- private void scheduleRefresh() => Scheduler.AddOnce(refresh);
+ private void scheduleRefresh()
+ {
+ Scheduler.AddOnce(refresh);
+ }
private void refresh()
{
ClearInternal();
- if (End == null)
- return;
-
OsuHitObject osuStart = Start.HitObject;
- OsuHitObject osuEnd = End.HitObject;
-
- if (osuEnd.NewCombo)
- return;
-
- if (osuStart is Spinner || osuEnd is Spinner)
- return;
-
- Vector2 startPosition = osuStart.EndPosition;
- Vector2 endPosition = osuEnd.Position;
double startTime = osuStart.GetEndTime();
+
+ LifetimeStart = startTime;
+
+ OsuHitObject osuEnd = End?.HitObject;
+
+ if (osuEnd == null || osuEnd.NewCombo || osuStart is Spinner || osuEnd is Spinner)
+ {
+ // ensure we always set a lifetime for full LifetimeManagementContainer benefits
+ LifetimeEnd = LifetimeStart;
+ return;
+ }
+
+ Vector2 startPosition = osuStart.StackedEndPosition;
+ Vector2 endPosition = osuEnd.StackedPosition;
double endTime = osuEnd.StartTime;
Vector2 distanceVector = endPosition - startPosition;
@@ -107,6 +113,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
float rotation = (float)(Math.Atan2(distanceVector.Y, distanceVector.X) * (180 / Math.PI));
double duration = endTime - startTime;
+ double? firstTransformStartTime = null;
+ double finalTransformEndTime = startTime;
+
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
{
float fraction = (float)d / distance;
@@ -125,16 +134,23 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
Scale = new Vector2(1.5f * osuEnd.Scale),
});
+ if (firstTransformStartTime == null)
+ firstTransformStartTime = fadeInTime;
+
using (fp.BeginAbsoluteSequence(fadeInTime))
{
fp.FadeIn(osuEnd.TimeFadeIn);
fp.ScaleTo(osuEnd.Scale, osuEnd.TimeFadeIn, Easing.Out);
fp.MoveTo(pointEndPosition, osuEnd.TimeFadeIn, Easing.Out);
fp.Delay(fadeOutTime - fadeInTime).FadeOut(osuEnd.TimeFadeIn);
- }
- fp.Expire(true);
+ finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn;
+ }
}
+
+ // todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed.
+ LifetimeStart = firstTransformStartTime ?? startTime;
+ LifetimeEnd = finalTransformEndTime;
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
index be192080f9..4d73e711bb 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointRenderer.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
///
/// Visualises connections between s.
///
- public class FollowPointRenderer : CompositeDrawable
+ public class FollowPointRenderer : LifetimeManagementContainer
{
///
/// All the s contained by this .
@@ -45,8 +45,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
/// The index of in .
private void addConnection(FollowPointConnection connection)
{
- AddInternal(connection);
-
// Groups are sorted by their start time when added such that the index can be used to post-process other surrounding connections
int index = connections.AddInPlace(connection, Comparer.Create((g1, g2) => g1.StartTime.Value.CompareTo(g2.StartTime.Value)));
@@ -74,6 +72,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
FollowPointConnection previousConnection = connections[index - 1];
previousConnection.End = connection.Start;
}
+
+ AddInternal(connection);
}
///
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
index 0dc5c9b4a0..c871089acd 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
@@ -4,6 +4,7 @@
using System;
using System.Linq;
using osu.Framework.Allocation;
+using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -214,9 +215,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
public class DefaultSliderBall : CompositeDrawable
{
+ private Box box;
+
[BackgroundDependencyLoader]
private void load(DrawableHitObject drawableObject, ISkinSource skin)
{
+ var slider = (DrawableSlider)drawableObject;
+
RelativeSizeAxes = Axes.Both;
float radius = skin.GetConfig(OsuSkinConfiguration.SliderPathRadius)?.Value ?? OsuHitObject.OBJECT_RADIUS;
@@ -231,14 +236,21 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
BorderThickness = 10,
BorderColour = Color4.White,
Alpha = 1,
- Child = new Box
+ Child = box = new Box
{
+ Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both,
Colour = Color4.White,
- Alpha = 0.4f,
+ AlwaysPresent = true,
+ Alpha = 0
}
};
+
+ slider.Tracking.BindValueChanged(trackingChanged, true);
}
+
+ private void trackingChanged(ValueChangedEvent tracking) =>
+ box.FadeTo(tracking.NewValue ? 0.6f : 0.05f, 200, Easing.OutQuint);
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
index c17d2275b8..127c36fcc0 100644
--- a/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
+++ b/osu.Game.Rulesets.Osu/Objects/SliderTailCircle.cs
@@ -4,7 +4,6 @@
using osu.Framework.Bindables;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
-using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects
@@ -23,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Objects
pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
}
- public override Judgement CreateJudgement() => new OsuSliderTailJudgement();
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
index 4e86662ec6..37df5ec540 100644
--- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
+++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs
@@ -5,7 +5,6 @@ using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Allocation;
-using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Batches;
using osu.Framework.Graphics.OpenGL.Vertices;
@@ -14,6 +13,7 @@ using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.Input.Events;
+using osu.Framework.Layout;
using osu.Framework.Timing;
using osuTK;
using osuTK.Graphics;
@@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
// -1 signals that the part is unusable, and should not be drawn
parts[i].InvalidationID = -1;
}
+
+ AddLayout(partSizeCache);
}
[BackgroundDependencyLoader]
@@ -72,20 +74,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
}
}
- private readonly Cached partSizeCache = new Cached();
+ private readonly LayoutValue partSizeCache = new LayoutValue(Invalidation.DrawInfo | Invalidation.RequiredParentSizeToFit | Invalidation.Presence);
private Vector2 partSize => partSizeCache.IsValid
? partSizeCache.Value
: (partSizeCache.Value = new Vector2(Texture.DisplayWidth, Texture.DisplayHeight) * DrawInfo.Matrix.ExtractScale().Xy);
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & (Invalidation.DrawInfo | Invalidation.RequiredParentSizeToFit | Invalidation.Presence)) > 0)
- partSizeCache.Invalidate();
-
- return base.Invalidate(invalidation, source, shallPropagate);
- }
-
///
/// The amount of time to fade the cursor trail pieces.
///
@@ -97,7 +91,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
{
base.Update();
- Invalidate(Invalidation.DrawNode, shallPropagate: false);
+ Invalidate(Invalidation.DrawNode);
const int fade_clock_reset_threshold = 1000000;
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
index f27e329e8e..303f0163b1 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
@@ -1,24 +1,16 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
-using osu.Framework.Allocation;
using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Judgements;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
-using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests
{
public class TestSceneSwellJudgements : PlayerTestScene
{
- protected new TestPlayer Player => (TestPlayer)base.Player;
-
public TestSceneSwellJudgements()
: base(new TaikoRuleset())
{
@@ -28,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
public void TestZeroTickTimeOffsets()
{
AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted);
- AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0));
+ AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.HitObject is SwellTick).All(r => r.TimeOffset == 0));
}
protected override bool Autoplay => true;
@@ -50,25 +42,5 @@ namespace osu.Game.Rulesets.Taiko.Tests
return beatmap;
}
-
- protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer();
-
- protected class TestPlayer : Player
- {
- public readonly List Results = new List();
-
- public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
-
- public TestPlayer()
- : base(false, false)
- {
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- ScoreProcessor.NewJudgement += r => Results.Add(r);
- }
- }
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
index 140433a523..2ab041e191 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
@@ -4,11 +4,9 @@
using System.Linq;
using NUnit.Framework;
using osu.Game.Beatmaps;
-using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Beatmaps;
using osu.Game.Rulesets.Taiko.Mods;
using osu.Game.Rulesets.Taiko.Objects;
-using osu.Game.Screens.Play;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Taiko.Tests
@@ -22,10 +20,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
protected override bool AllowFail => true;
- protected override Player CreatePlayer(Ruleset ruleset)
+ protected override TestPlayer CreatePlayer(Ruleset ruleset)
{
SelectedMods.Value = SelectedMods.Value.Concat(new[] { new TaikoModSuddenDeath() }).ToArray();
- return new ScoreAccessiblePlayer();
+ return base.CreatePlayer(ruleset);
}
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) =>
@@ -49,20 +47,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
AddStep("Setup judgements", () =>
{
judged = false;
- ((ScoreAccessiblePlayer)Player).ScoreProcessor.NewJudgement += b => judged = true;
+ Player.ScoreProcessor.NewJudgement += b => judged = true;
});
AddUntilStep("swell judged", () => judged);
AddAssert("not failed", () => !Player.HasFailed);
}
-
- private class ScoreAccessiblePlayer : TestPlayer
- {
- public ScoreAccessiblePlayer()
- : base(false, false)
- {
- }
-
- public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
- }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
index b7db3307ad..1253b7c8ae 100644
--- a/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModFlashlight.cs
@@ -2,8 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
-using osu.Framework.Caching;
using osu.Framework.Graphics;
+using osu.Framework.Layout;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Taiko.Objects;
using osu.Game.Rulesets.Taiko.UI;
@@ -30,13 +30,15 @@ namespace osu.Game.Rulesets.Taiko.Mods
private class TaikoFlashlight : Flashlight
{
- private readonly Cached flashlightProperties = new Cached();
+ private readonly LayoutValue flashlightProperties = new LayoutValue(Invalidation.DrawSize);
private readonly TaikoPlayfield taikoPlayfield;
public TaikoFlashlight(TaikoPlayfield taikoPlayfield)
{
this.taikoPlayfield = taikoPlayfield;
FlashlightSize = new Vector2(0, getSizeFor(0));
+
+ AddLayout(flashlightProperties);
}
private float getSizeFor(int combo)
@@ -56,16 +58,6 @@ namespace osu.Game.Rulesets.Taiko.Mods
protected override string FragmentShader => "CircularFlashlight";
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & Invalidation.DrawSize) > 0)
- {
- flashlightProperties.Invalidate();
- }
-
- return base.Invalidate(invalidation, source, shallPropagate);
- }
-
protected override void Update()
{
base.Update();
diff --git a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
index 2afbbc737c..6306195704 100644
--- a/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/BarLine.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Taiko.Objects
@@ -8,5 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Objects
public class BarLine : TaikoHitObject, IBarLine
{
public bool Major { get; set; }
+
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
index 1a5a797f28..e9caabbcc8 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableBarLine.cs
@@ -54,5 +54,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Alpha = 0.75f
});
}
+
+ protected override void UpdateStateTransforms(ArmedState state) => this.FadeOut(150);
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
index 91f4d3dbe7..bdc0478195 100644
--- a/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/SwellTick.cs
@@ -3,13 +3,12 @@
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.Taiko.Judgements;
namespace osu.Game.Rulesets.Taiko.Objects
{
public class SwellTick : TaikoHitObject
{
- public override Judgement CreateJudgement() => new TaikoSwellTickJudgement();
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
diff --git a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
index 244e37f017..885abb61b5 100644
--- a/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneDrainingHealthProcessor.cs
@@ -154,6 +154,7 @@ namespace osu.Game.Tests.Gameplay
private class JudgeableHitObject : HitObject
{
public override Judgement CreateJudgement() => new Judgement();
+ protected override HitWindows CreateHitWindows() => new HitWindows();
}
}
}
diff --git a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
index 17dc27543d..7a89642e11 100644
--- a/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
+++ b/osu.Game.Tests/Gameplay/TestSceneHitObjectAccentColour.cs
@@ -11,8 +11,8 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.Testing;
using osu.Game.Audio;
-using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
@@ -78,7 +78,7 @@ namespace osu.Game.Tests.Gameplay
}
}
- private class TestHitObjectWithCombo : HitObject, IHasComboInformation
+ private class TestHitObjectWithCombo : ConvertHitObject, IHasComboInformation
{
public bool NewCombo { get; } = false;
public int ComboOffset { get; } = 0;
diff --git a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
index 6d014ca1ca..06a155e78b 100644
--- a/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
+++ b/osu.Game.Tests/Visual/Background/TestSceneUserDimBackgrounds.cs
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Background
private DummySongSelect songSelect;
private TestPlayerLoader playerLoader;
- private TestPlayer player;
+ private LoadBlockingTestPlayer player;
private BeatmapManager manager;
private RulesetStore rulesets;
@@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.Background
public void PlayerLoaderSettingsHoverTest()
{
setupUserSettings();
- AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer { BlockLoad = true })));
+ AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new LoadBlockingTestPlayer { BlockLoad = true })));
AddUntilStep("Wait for Player Loader to load", () => playerLoader?.IsLoaded ?? false);
AddAssert("Background retained from song select", () => songSelect.IsBackgroundCurrent());
AddStep("Trigger background preview", () =>
@@ -268,7 +268,7 @@ namespace osu.Game.Tests.Visual.Background
{
setupUserSettings();
- AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new TestPlayer(allowPause))));
+ AddStep("Start player loader", () => songSelect.Push(playerLoader = new TestPlayerLoader(player = new LoadBlockingTestPlayer(allowPause))));
AddUntilStep("Wait for Player Loader to load", () => playerLoader.IsLoaded);
AddStep("Move mouse to center of screen", () => InputManager.MoveMouseTo(playerLoader.ScreenPos));
@@ -347,7 +347,7 @@ namespace osu.Game.Tests.Visual.Background
public bool IsBlurCorrect() => ((FadeAccessibleBackground)Background).CurrentBlur == new Vector2(BACKGROUND_BLUR);
}
- private class TestPlayer : Visual.TestPlayer
+ private class LoadBlockingTestPlayer : TestPlayer
{
protected override BackgroundScreen CreateBackground() => new FadeAccessibleBackground(Beatmap.Value);
@@ -360,7 +360,7 @@ namespace osu.Game.Tests.Visual.Background
public readonly Bindable ReplacesBackground = new Bindable();
public readonly Bindable IsPaused = new Bindable();
- public TestPlayer(bool allowPause = true)
+ public LoadBlockingTestPlayer(bool allowPause = true)
: base(allowPause)
{
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 4daab8d137..756f31e0bf 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -5,7 +5,6 @@ using System.ComponentModel;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
-using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
using osu.Game.Storyboards;
@@ -14,20 +13,22 @@ namespace osu.Game.Tests.Visual.Gameplay
[Description("Player instantiated with an autoplay mod.")]
public class TestSceneAutoplay : TestSceneAllRulesetPlayers
{
+ protected new TestPlayer Player => (TestPlayer)base.Player;
+
private ClockBackedTestWorkingBeatmap.TrackVirtualManual track;
protected override Player CreatePlayer(Ruleset ruleset)
{
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
- return new ScoreAccessiblePlayer();
+ return new TestPlayer(false, false);
}
protected override void AddCheckSteps()
{
- AddUntilStep("score above zero", () => ((ScoreAccessiblePlayer)Player).ScoreProcessor.TotalScore.Value > 0);
- AddUntilStep("key counter counted keys", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
+ AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
+ AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
AddStep("rewind", () => track.Seek(-10000));
- AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
+ AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
}
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
@@ -38,18 +39,5 @@ namespace osu.Game.Tests.Visual.Gameplay
return working;
}
-
- private class ScoreAccessiblePlayer : TestPlayer
- {
- public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
- public new HUDOverlay HUDOverlay => base.HUDOverlay;
-
- public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
-
- public ScoreAccessiblePlayer()
- : base(false, false)
- {
- }
- }
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
index 46f62b9541..b25b81c9af 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneDrawableScrollingRuleset.cs
@@ -20,6 +20,7 @@ using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.UI;
@@ -289,7 +290,7 @@ namespace osu.Game.Tests.Visual.Gameplay
#region HitObject
- private class TestHitObject : HitObject, IHasEndTime
+ private class TestHitObject : ConvertHitObject, IHasEndTime
{
public double EndTime { get; set; }
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
index 78c3b22fb9..310746d179 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -11,12 +10,8 @@ using osu.Framework.Utils;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
-using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Rulesets.UI;
-using osu.Game.Screens.Play;
using osu.Game.Storyboards;
using osuTK;
@@ -24,8 +19,6 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneGameplayRewinding : PlayerTestScene
{
- private RulesetExposingPlayer player => (RulesetExposingPlayer)Player;
-
[Resolved]
private AudioManager audioManager { get; set; }
@@ -48,13 +41,13 @@ namespace osu.Game.Tests.Visual.Gameplay
{
AddUntilStep("wait for track to start running", () => track.IsRunning);
addSeekStep(3000);
- AddAssert("all judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
- AddUntilStep("key counter counted keys", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
- AddStep("clear results", () => player.AppliedResults.Clear());
+ AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
+ AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses >= 7));
+ AddStep("clear results", () => Player.Results.Clear());
addSeekStep(0);
- AddAssert("none judged", () => player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
- AddUntilStep("key counters reset", () => player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
- AddAssert("no results triggered", () => player.AppliedResults.Count == 0);
+ AddAssert("none judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
+ AddUntilStep("key counters reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
+ AddAssert("no results triggered", () => Player.Results.Count == 0);
}
private void addSeekStep(double time)
@@ -62,13 +55,13 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep($"seek to {time}", () => track.Seek(time));
// Allow a few frames of lenience
- AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
+ AddUntilStep("wait for seek to finish", () => Precision.AlmostEquals(time, Player.DrawableRuleset.FrameStableClock.CurrentTime, 100));
}
- protected override Player CreatePlayer(Ruleset ruleset)
+ protected override TestPlayer CreatePlayer(Ruleset ruleset)
{
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
- return new RulesetExposingPlayer();
+ return base.CreatePlayer(ruleset);
}
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
@@ -89,29 +82,5 @@ namespace osu.Game.Tests.Visual.Gameplay
return beatmap;
}
-
- private class RulesetExposingPlayer : Player
- {
- public readonly List AppliedResults = new List();
-
- public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
-
- public new HUDOverlay HUDOverlay => base.HUDOverlay;
-
- public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
-
- public new DrawableRuleset DrawableRuleset => base.DrawableRuleset;
-
- public RulesetExposingPlayer()
- : base(false, false)
- {
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- ScoreProcessor.NewJudgement += r => AppliedResults.Add(r);
- }
- }
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
index 8904b54b0d..1527cba6fc 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
@@ -2,16 +2,17 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
-using osu.Game.Rulesets.Objects;
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Judgements;
using osu.Framework.Utils;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Threading;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Mania.Scoring;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Scoring;
@@ -43,6 +44,22 @@ namespace osu.Game.Tests.Visual.Gameplay
AddRepeatStep("New max negative", () => newJudgement(-hitWindows.WindowFor(HitResult.Meh)), 20);
AddRepeatStep("New max positive", () => newJudgement(hitWindows.WindowFor(HitResult.Meh)), 20);
AddStep("New fixed judgement (50ms)", () => newJudgement(50));
+
+ AddStep("Judgement barrage", () =>
+ {
+ int runCount = 0;
+
+ ScheduledDelegate del = null;
+
+ del = Scheduler.AddDelayed(() =>
+ {
+ newJudgement(runCount++ / 10f);
+
+ if (runCount == 500)
+ // ReSharper disable once AccessToModifiedClosure
+ del?.Cancel();
+ }, 10, true);
+ });
}
[Test]
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
index ad5bab4681..944e6ca6be 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs
@@ -11,7 +11,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Cursor;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
-using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play;
using osuTK;
using osuTK.Input;
@@ -282,14 +281,10 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override bool AllowFail => true;
- protected override Player CreatePlayer(Ruleset ruleset) => new PausePlayer();
+ protected override TestPlayer CreatePlayer(Ruleset ruleset) => new PausePlayer();
protected class PausePlayer : TestPlayer
{
- public new HealthProcessor HealthProcessor => base.HealthProcessor;
-
- public new HUDOverlay HUDOverlay => base.HUDOverlay;
-
public bool FailOverlayVisible => FailOverlay.State.Value == Visibility.Visible;
public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs
index 3513b6c25a..a83320048b 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePauseWhenInactive.cs
@@ -9,15 +9,12 @@ using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
-using osu.Game.Screens.Play;
namespace osu.Game.Tests.Visual.Gameplay
{
[HeadlessTest] // we alter unsafe properties on the game host to test inactive window state.
public class TestScenePauseWhenInactive : PlayerTestScene
{
- protected new TestPlayer Player => (TestPlayer)base.Player;
-
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
{
var beatmap = (Beatmap)base.CreateBeatmap(ruleset);
@@ -46,6 +43,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert("time of pause is after gameplay start time", () => Player.GameplayClockContainer.GameplayClock.CurrentTime >= Player.DrawableRuleset.GameplayStartTime);
}
- protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true);
+ protected override TestPlayer CreatePlayer(Ruleset ruleset) => new TestPlayer(true, true, true);
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
index 100f99d130..175f909a5a 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLoader.cs
@@ -9,7 +9,6 @@ using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Audio;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
@@ -307,17 +306,7 @@ namespace osu.Game.Tests.Visual.Gameplay
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
}
- private class TestPlayer : Visual.TestPlayer
- {
- public new Bindable> Mods => base.Mods;
-
- public TestPlayer(bool allowPause = true, bool showResults = true)
- : base(allowPause, showResults)
- {
- }
- }
-
- protected class SlowLoadPlayer : Visual.TestPlayer
+ protected class SlowLoadPlayer : TestPlayer
{
public readonly ManualResetEventSlim AllowLoad = new ManualResetEventSlim(false);
diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
index 70d71d0952..0d64eb651f 100644
--- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
+++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs
@@ -62,14 +62,7 @@ namespace osu.Game.Tests.Visual.Navigation
var frameworkConfig = host.Dependencies.Get();
frameworkConfig.GetBindable(FrameworkSetting.CursorSensitivity).Disabled = false;
- Game = new TestOsuGame(LocalStorage, API);
- Game.SetHost(host);
-
- // todo: this can be removed once we can run audio tracks without a device present
- // see https://github.com/ppy/osu/issues/1302
- Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
-
- Add(Game);
+ CreateGame();
});
AddUntilStep("Wait for load", () => Game.IsLoaded);
@@ -78,6 +71,18 @@ namespace osu.Game.Tests.Visual.Navigation
ConfirmAtMainMenu();
}
+ protected void CreateGame()
+ {
+ Game = new TestOsuGame(LocalStorage, API);
+ Game.SetHost(host);
+
+ // todo: this can be removed once we can run audio tracks without a device present
+ // see https://github.com/ppy/osu/issues/1302
+ Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
+
+ Add(Game);
+ }
+
protected void PushAndConfirm(Func newScreen)
{
Screen screen = null;
@@ -97,12 +102,17 @@ namespace osu.Game.Tests.Visual.Navigation
public new SettingsPanel Settings => base.Settings;
+ public new MusicController MusicController => base.MusicController;
+
public new OsuConfigManager LocalConfig => base.LocalConfig;
public new Bindable Beatmap => base.Beatmap;
public new Bindable Ruleset => base.Ruleset;
+ // if we don't do this, when running under nUnit the version that gets populated is that of nUnit.
+ public override string Version => "test game";
+
protected override Loader CreateLoader() => new TestLoader();
public new void PerformFromScreen(Action action, IEnumerable validScreens = null) => base.PerformFromScreen(action, validScreens);
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
index 8258cc9465..9d603ac471 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs
@@ -114,6 +114,22 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
}
+ [Test]
+ public void TestWaitForNextTrackInMenu()
+ {
+ bool trackCompleted = false;
+
+ AddUntilStep("Wait for music controller", () => Game.MusicController.IsLoaded);
+ AddStep("Seek close to end", () =>
+ {
+ Game.MusicController.SeekTo(Game.Beatmap.Value.Track.Length - 1000);
+ Game.Beatmap.Value.Track.Completed += () => trackCompleted = true;
+ });
+
+ AddUntilStep("Track was completed", () => trackCompleted);
+ AddUntilStep("Track was restarted", () => Game.Beatmap.Value.Track.IsRunning);
+ }
+
private void pushEscape() =>
AddStep("Press escape", () => pressAndRelease(Key.Escape));
diff --git a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs
new file mode 100644
index 0000000000..c0b77b580e
--- /dev/null
+++ b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs
@@ -0,0 +1,41 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Framework.Utils;
+using osu.Game.Configuration;
+
+namespace osu.Game.Tests.Visual.Navigation
+{
+ public class TestSettingsMigration : OsuGameTestScene
+ {
+ public override void RecycleLocalStorage()
+ {
+ base.RecycleLocalStorage();
+
+ using (var config = new OsuConfigManager(LocalStorage))
+ {
+ config.Set(OsuSetting.Version, "2020.101.0");
+ config.Set(OsuSetting.DisplayStarsMaximum, 10.0);
+ }
+ }
+
+ [Test]
+ public void TestDisplayStarsMigration()
+ {
+ AddAssert("config has migrated value", () => Precision.AlmostEquals(Game.LocalConfig.Get(OsuSetting.DisplayStarsMaximum), 10.1));
+
+ AddStep("set value again", () => Game.LocalConfig.Set(OsuSetting.DisplayStarsMaximum, 10));
+
+ AddStep("force save config", () => Game.LocalConfig.Save());
+
+ AddStep("remove game", () => Remove(Game));
+
+ AddStep("create game again", CreateGame);
+
+ AddUntilStep("Wait for load", () => Game.IsLoaded);
+
+ AddAssert("config did not migrate value", () => Precision.AlmostEquals(Game.LocalConfig.Get(OsuSetting.DisplayStarsMaximum), 10));
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
index 1217ce6b42..a28a0107a1 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs
@@ -13,6 +13,8 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osuTK;
+using JetBrains.Annotations;
+using NUnit.Framework;
namespace osu.Game.Tests.Visual.Online
{
@@ -30,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online
private readonly BindableBool showDeleted = new BindableBool();
private readonly Container content;
+ private TestCommentsPage commentsPage;
+
public TestSceneCommentsPage()
{
Add(new FillFlowContainer
@@ -57,27 +61,40 @@ namespace osu.Game.Tests.Visual.Online
}
}
});
+ }
- AddStep("load comments", () => createPage(comment_bundle));
- AddStep("load empty comments", () => createPage(empty_comment_bundle));
+ [Test]
+ public void TestAppendDuplicatedComment()
+ {
+ AddStep("Create page", () => createPage(getCommentBundle()));
+ AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
+ AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle()));
+ AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10);
+ }
+
+ [Test]
+ public void TestEmptyBundle()
+ {
+ AddStep("Create page", () => createPage(getEmptyCommentBundle()));
+ AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0);
}
private void createPage(CommentBundle commentBundle)
{
+ commentsPage = null;
content.Clear();
- content.Add(new CommentsPage(commentBundle)
+ content.Add(commentsPage = new TestCommentsPage(commentBundle)
{
ShowDeleted = { BindTarget = showDeleted }
});
}
- private static readonly CommentBundle empty_comment_bundle = new CommentBundle
+ private CommentBundle getEmptyCommentBundle() => new CommentBundle
{
Comments = new List(),
- Total = 0,
};
- private static readonly CommentBundle comment_bundle = new CommentBundle
+ private CommentBundle getCommentBundle() => new CommentBundle
{
Comments = new List
{
@@ -90,6 +107,33 @@ namespace osu.Game.Tests.Visual.Online
VotesCount = 5
},
new Comment
+ {
+ Id = 100,
+ Message = "This comment has \"load replies\" button because it has unloaded replies",
+ LegacyName = "TestUser1100",
+ CreatedAt = DateTimeOffset.Now,
+ VotesCount = 5,
+ RepliesCount = 2,
+ },
+ new Comment
+ {
+ Id = 111,
+ Message = "This comment has \"Show More\" button because it has unloaded replies, but some of them are loaded",
+ LegacyName = "TestUser1111",
+ CreatedAt = DateTimeOffset.Now,
+ VotesCount = 100,
+ RepliesCount = 2,
+ },
+ new Comment
+ {
+ Id = 112,
+ ParentId = 111,
+ Message = "I'm here to make my parent work",
+ LegacyName = "someone",
+ CreatedAt = DateTimeOffset.Now,
+ VotesCount = 2,
+ },
+ new Comment
{
Id = 2,
Message = "This comment has been deleted :( but visible for admins",
@@ -155,8 +199,34 @@ namespace osu.Game.Tests.Visual.Online
Username = "Good_Admin"
}
},
- TopLevelCount = 4,
- Total = 7
};
+
+ private CommentBundle getCommentSubBundle() => new CommentBundle
+ {
+ Comments = new List
+ {
+ new Comment
+ {
+ Id = 1,
+ Message = "Simple test comment",
+ LegacyName = "TestUser1",
+ CreatedAt = DateTimeOffset.Now,
+ VotesCount = 5
+ },
+ },
+ IncludedComments = new List(),
+ };
+
+ private class TestCommentsPage : CommentsPage
+ {
+ public TestCommentsPage(CommentBundle commentBundle)
+ : base(commentBundle)
+ {
+ }
+
+ public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle);
+
+ public int DictionaryLength => CommentDictionary.Count;
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
index 731cb62518..cb08cded37 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
@@ -14,7 +15,8 @@ using osuTK;
namespace osu.Game.Tests.Visual.Online
{
- public class TestSceneDirectPanel : OsuTestScene
+ [Cached(typeof(IPreviewTrackOwner))]
+ public class TestSceneDirectPanel : OsuTestScene, IPreviewTrackOwner
{
public override IReadOnlyList RequiredTypes => new[]
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs
index 3c2735ca56..9591d53b24 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online);
AddUntilStep("children are visible", () => onlineView.ViewTarget.IsPresent);
- AddUntilStep("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent);
+ AddUntilStep("loading animation is not visible", () => !onlineView.LoadingSpinner.IsPresent);
}
[Test]
@@ -44,7 +44,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline);
AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent);
- AddUntilStep("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent);
+ AddUntilStep("loading animation is not visible", () => !onlineView.LoadingSpinner.IsPresent);
}
[Test]
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Online
AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting);
AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent);
- AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent);
+ AddUntilStep("loading animation is visible", () => onlineView.LoadingSpinner.IsPresent);
}
[Test]
@@ -62,12 +62,12 @@ namespace osu.Game.Tests.Visual.Online
AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing);
AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent);
- AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent);
+ AddUntilStep("loading animation is visible", () => onlineView.LoadingSpinner.IsPresent);
}
private class TestOnlineViewContainer : OnlineViewContainer
{
- public new LoadingAnimation LoadingAnimation => base.LoadingAnimation;
+ public new LoadingSpinner LoadingSpinner => base.LoadingSpinner;
public CompositeDrawable ViewTarget => base.Content;
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
index 656402e713..8542a5e46e 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
@@ -8,7 +8,6 @@ using osu.Game.Overlays.Rankings.Tables;
using osu.Framework.Graphics;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets;
-using osu.Game.Graphics.UserInterface;
using System.Threading;
using osu.Game.Online.API;
using osu.Game.Rulesets.Osu;
@@ -16,6 +15,7 @@ using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Catch;
using osu.Framework.Allocation;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
@@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Green);
private readonly BasicScrollContainer scrollFlow;
- private readonly DimmedLoadingLayer loading;
+ private readonly LoadingLayer loading;
private CancellationTokenSource cancellationToken;
private APIRequest request;
@@ -56,7 +56,7 @@ namespace osu.Game.Tests.Visual.Online
RelativeSizeAxes = Axes.Both,
Width = 0.8f,
},
- loading = new DimmedLoadingLayer(),
+ loading = new LoadingLayer(),
};
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
index 54f06d6ad2..80fcef2ed2 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
@@ -2,9 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
+using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets;
using osu.Game.Users;
using osuTK;
@@ -13,13 +15,19 @@ namespace osu.Game.Tests.Visual.Online
[TestFixture]
public class TestSceneUserPanel : OsuTestScene
{
- private readonly UserPanel peppy;
+ private readonly Bindable activity = new Bindable();
- public TestSceneUserPanel()
+ private UserPanel peppy;
+
+ [Resolved]
+ private RulesetStore rulesetStore { get; set; }
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
{
UserPanel flyte;
- Add(new FillFlowContainer
+ Child = new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -44,34 +52,38 @@ namespace osu.Game.Tests.Visual.Online
SupportLevel = 3,
}) { Width = 300 },
},
- });
+ };
flyte.Status.Value = new UserStatusOnline();
peppy.Status.Value = null;
- }
-
- [Test]
- public void UserStatusesTests()
- {
- AddStep("online", () => { peppy.Status.Value = new UserStatusOnline(); });
- AddStep(@"do not disturb", () => { peppy.Status.Value = new UserStatusDoNotDisturb(); });
- AddStep(@"offline", () => { peppy.Status.Value = new UserStatusOffline(); });
- AddStep(@"null status", () => { peppy.Status.Value = null; });
- }
-
- [Test]
- public void UserActivitiesTests()
- {
- Bindable activity = new Bindable();
-
peppy.Activity.BindTo(activity);
+ });
- AddStep("idle", () => { activity.Value = null; });
- AddStep("spectating", () => { activity.Value = new UserActivity.Spectating(); });
- AddStep("solo", () => { activity.Value = new UserActivity.SoloGame(null, null); });
- AddStep("choosing", () => { activity.Value = new UserActivity.ChoosingBeatmap(); });
- AddStep("editing", () => { activity.Value = new UserActivity.Editing(null); });
- AddStep("modding", () => { activity.Value = new UserActivity.Modding(); });
+ [Test]
+ public void TestUserStatus()
+ {
+ AddStep("online", () => peppy.Status.Value = new UserStatusOnline());
+ AddStep("do not disturb", () => peppy.Status.Value = new UserStatusDoNotDisturb());
+ AddStep("offline", () => peppy.Status.Value = new UserStatusOffline());
+ AddStep("null status", () => peppy.Status.Value = null);
}
+
+ [Test]
+ public void TestUserActivity()
+ {
+ AddStep("set online status", () => peppy.Status.Value = new UserStatusOnline());
+
+ AddStep("idle", () => activity.Value = null);
+ AddStep("spectating", () => activity.Value = new UserActivity.Spectating());
+ AddStep("solo (osu!)", () => activity.Value = soloGameStatusForRuleset(0));
+ AddStep("solo (osu!taiko)", () => activity.Value = soloGameStatusForRuleset(1));
+ AddStep("solo (osu!catch)", () => activity.Value = soloGameStatusForRuleset(2));
+ AddStep("solo (osu!mania)", () => activity.Value = soloGameStatusForRuleset(3));
+ AddStep("choosing", () => activity.Value = new UserActivity.ChoosingBeatmap());
+ AddStep("editing", () => activity.Value = new UserActivity.Editing(null));
+ AddStep("modding", () => activity.Value = new UserActivity.Modding());
+ }
+
+ private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.SoloGame(null, rulesetStore.GetRuleset(rulesetId));
}
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs b/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs
index 0f41247571..15cfd3ee54 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserRequest.cs
@@ -12,8 +12,8 @@ using osu.Game.Rulesets.Mania;
using osu.Game.Users;
using osu.Framework.Graphics;
using osu.Game.Graphics.Sprites;
-using osu.Game.Rulesets.Taiko;
using osu.Game.Graphics.UserInterface;
+using osu.Game.Rulesets.Taiko;
namespace osu.Game.Tests.Visual.Online
{
@@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Online
private readonly Bindable user = new Bindable();
private GetUserRequest request;
- private readonly DimmedLoadingLayer loading;
+ private readonly LoadingLayer loading;
public TestSceneUserRequest()
{
@@ -40,10 +40,7 @@ namespace osu.Game.Tests.Visual.Online
{
User = { BindTarget = user }
},
- loading = new DimmedLoadingLayer
- {
- Alpha = 0
- }
+ loading = new LoadingLayer()
}
});
}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs
index 8197cf72de..770cef8f1b 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneVotePill.cs
@@ -7,6 +7,8 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Game.Overlays.Comments;
using osu.Game.Online.API.Requests.Responses;
+using osu.Framework.Allocation;
+using osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
{
@@ -18,6 +20,9 @@ namespace osu.Game.Tests.Visual.Online
typeof(VotePill)
};
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
private VotePill votePill;
[Test]
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
index f49d7a14a6..e02ebf3be1 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs
@@ -13,6 +13,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Taiko;
@@ -194,7 +195,7 @@ namespace osu.Game.Tests.Visual.SongSelect
public new BufferedWedgeInfo Info => base.Info;
}
- private class TestHitObject : HitObject, IHasPosition
+ private class TestHitObject : ConvertHitObject, IHasPosition
{
public float X { get; } = 0;
public float Y { get; } = 0;
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 9474c08c5a..51d302123b 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -502,6 +502,72 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID);
}
+ [Test]
+ public void TestDifficultyIconSelecting()
+ {
+ addRulesetImportStep(0);
+ createSongSelect();
+
+ DrawableCarouselBeatmapSet set = null;
+ AddStep("Find the DrawableCarouselBeatmapSet", () =>
+ {
+ set = songSelect.Carousel.ChildrenOfType().First();
+ });
+
+ DrawableCarouselBeatmapSet.FilterableDifficultyIcon difficultyIcon = null;
+ AddStep("Find an icon", () =>
+ {
+ difficultyIcon = set.ChildrenOfType()
+ .First(icon => getDifficultyIconIndex(set, icon) != getCurrentBeatmapIndex());
+ });
+ AddStep("Click on a difficulty", () =>
+ {
+ InputManager.MoveMouseTo(difficultyIcon);
+
+ InputManager.PressButton(MouseButton.Left);
+ InputManager.ReleaseButton(MouseButton.Left);
+ });
+ AddAssert("Selected beatmap correct", () => getCurrentBeatmapIndex() == getDifficultyIconIndex(set, difficultyIcon));
+
+ double? maxBPM = null;
+ AddStep("Filter some difficulties", () => songSelect.Carousel.Filter(new FilterCriteria
+ {
+ BPM = new FilterCriteria.OptionalRange
+ {
+ Min = maxBPM = songSelect.Carousel.SelectedBeatmapSet.MaxBPM,
+ IsLowerInclusive = true
+ }
+ }));
+
+ DrawableCarouselBeatmapSet.FilterableDifficultyIcon filteredIcon = null;
+ AddStep("Get filtered icon", () =>
+ {
+ var filteredBeatmap = songSelect.Carousel.SelectedBeatmapSet.Beatmaps.Find(b => b.BPM < maxBPM);
+ int filteredBeatmapIndex = getBeatmapIndex(filteredBeatmap.BeatmapSet, filteredBeatmap);
+ filteredIcon = set.ChildrenOfType().ElementAt(filteredBeatmapIndex);
+ });
+
+ int? previousID = null;
+ AddStep("Store current ID", () => previousID = songSelect.Carousel.SelectedBeatmap.ID);
+ AddStep("Click on a filtered difficulty", () =>
+ {
+ InputManager.MoveMouseTo(filteredIcon);
+
+ InputManager.PressButton(MouseButton.Left);
+ InputManager.ReleaseButton(MouseButton.Left);
+ });
+ AddAssert("Selected beatmap has not changed", () => songSelect.Carousel.SelectedBeatmap.ID == previousID);
+ }
+
+ private int getBeatmapIndex(BeatmapSetInfo set, BeatmapInfo info) => set.Beatmaps.FindIndex(b => b == info);
+
+ private int getCurrentBeatmapIndex() => getBeatmapIndex(songSelect.Carousel.SelectedBeatmapSet, songSelect.Carousel.SelectedBeatmap);
+
+ private int getDifficultyIconIndex(DrawableCarouselBeatmapSet set, DrawableCarouselBeatmapSet.FilterableDifficultyIcon icon)
+ {
+ return set.ChildrenOfType().ToList().FindIndex(i => i == icon);
+ }
+
private void addRulesetImportStep(int id) => AddStep($"import test map for ruleset {id}", () => importForRuleset(id));
private void importForRuleset(int id) => manager.Import(createTestBeatmapSet(getImportId(), rulesets.AvailableRulesets.Where(r => r.ID == id).ToArray())).Wait();
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs
new file mode 100644
index 0000000000..7b0b644dab
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneCommentEditor.cs
@@ -0,0 +1,157 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Comments;
+using osuTK;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneCommentEditor : ManualInputManagerTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CommentEditor),
+ typeof(CancellableCommentEditor),
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
+ private TestCommentEditor commentEditor;
+ private TestCancellableCommentEditor cancellableCommentEditor;
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ Add(new FillFlowContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ AutoSizeAxes = Axes.Y,
+ Width = 800,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 20),
+ Children = new Drawable[]
+ {
+ commentEditor = new TestCommentEditor(),
+ cancellableCommentEditor = new TestCancellableCommentEditor()
+ }
+ }));
+
+ [Test]
+ public void TestCommitViaKeyboard()
+ {
+ AddStep("click on text box", () =>
+ {
+ InputManager.MoveMouseTo(commentEditor);
+ InputManager.Click(MouseButton.Left);
+ });
+ AddStep("enter text", () => commentEditor.Current.Value = "text");
+
+ AddStep("press Enter", () => press(Key.Enter));
+
+ AddAssert("text committed", () => commentEditor.CommittedText == "text");
+ AddAssert("button is loading", () => commentEditor.IsLoading);
+ }
+
+ [Test]
+ public void TestCommitViaKeyboardWhenEmpty()
+ {
+ AddStep("click on text box", () =>
+ {
+ InputManager.MoveMouseTo(commentEditor);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddStep("press Enter", () => press(Key.Enter));
+
+ AddAssert("no text committed", () => commentEditor.CommittedText == null);
+ AddAssert("button is not loading", () => !commentEditor.IsLoading);
+ }
+
+ [Test]
+ public void TestCommitViaButton()
+ {
+ AddStep("click on text box", () =>
+ {
+ InputManager.MoveMouseTo(commentEditor);
+ InputManager.Click(MouseButton.Left);
+ });
+ AddStep("enter text", () => commentEditor.Current.Value = "some other text");
+
+ AddStep("click submit", () =>
+ {
+ InputManager.MoveMouseTo(commentEditor.ButtonsContainer);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddAssert("text committed", () => commentEditor.CommittedText == "some other text");
+ AddAssert("button is loading", () => commentEditor.IsLoading);
+ }
+
+ [Test]
+ public void TestCancelAction()
+ {
+ AddStep("click cancel button", () =>
+ {
+ InputManager.MoveMouseTo(cancellableCommentEditor.ButtonsContainer);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddAssert("cancel action fired", () => cancellableCommentEditor.Cancelled);
+ }
+
+ private void press(Key key)
+ {
+ InputManager.PressKey(key);
+ InputManager.ReleaseKey(key);
+ }
+
+ private class TestCommentEditor : CommentEditor
+ {
+ public new Bindable Current => base.Current;
+ public new FillFlowContainer ButtonsContainer => base.ButtonsContainer;
+
+ public string CommittedText { get; private set; }
+
+ public TestCommentEditor()
+ {
+ OnCommit = onCommit;
+ }
+
+ private void onCommit(string value)
+ {
+ CommittedText = value;
+ Scheduler.AddDelayed(() => IsLoading = false, 1000);
+ }
+
+ protected override string FooterText => @"Footer text. And it is pretty long. Cool.";
+ protected override string CommitButtonText => @"Commit";
+ protected override string TextBoxPlaceholder => @"This text box is empty";
+ }
+
+ private class TestCancellableCommentEditor : CancellableCommentEditor
+ {
+ public new FillFlowContainer ButtonsContainer => base.ButtonsContainer;
+ protected override string FooterText => @"Wow, another one. Sicc";
+
+ public bool Cancelled { get; private set; }
+
+ public TestCancellableCommentEditor()
+ {
+ OnCancel = () => Cancelled = true;
+ }
+
+ protected override string CommitButtonText => @"Save";
+ protected override string TextBoxPlaceholder => @"Multiline textboxes soon";
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs
new file mode 100644
index 0000000000..7e9654715b
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingLayer.cs
@@ -0,0 +1,106 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneLoadingLayer : OsuTestScene
+ {
+ private Drawable dimContent;
+ private LoadingLayer overlay;
+
+ public override IReadOnlyList RequiredTypes => new[] { typeof(LoadingSpinner) };
+
+ private Container content;
+
+ [SetUp]
+ public void SetUp() => Schedule(() =>
+ {
+ Children = new[]
+ {
+ content = new Container
+ {
+ Size = new Vector2(300),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Children = new[]
+ {
+ new Box
+ {
+ Colour = Color4.SlateGray,
+ RelativeSizeAxes = Axes.Both,
+ },
+ dimContent = new FillFlowContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(10),
+ RelativeSizeAxes = Axes.Both,
+ Size = new Vector2(0.9f),
+ Children = new Drawable[]
+ {
+ new OsuSpriteText { Text = "Sample content" },
+ new TriangleButton { Text = "can't puush me", Width = 200, },
+ new TriangleButton { Text = "puush me", Width = 200, Action = () => { } },
+ }
+ },
+ overlay = new LoadingLayer(dimContent),
+ }
+ },
+ };
+ });
+
+ [Test]
+ public void TestShowHide()
+ {
+ AddAssert("not visible", () => !overlay.IsPresent);
+
+ AddStep("show", () => overlay.Show());
+
+ AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
+
+ AddStep("hide", () => overlay.Hide());
+
+ AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
+ }
+
+ [Test]
+ public void TestContentRestoreOnDispose()
+ {
+ AddAssert("not visible", () => !overlay.IsPresent);
+
+ AddStep("show", () => overlay.Show());
+
+ AddUntilStep("wait for content dim", () => dimContent.Colour != Color4.White);
+
+ AddStep("expire", () => overlay.Expire());
+
+ AddUntilStep("wait for content restore", () => dimContent.Colour == Color4.White);
+ }
+
+ [Test]
+ public void TestLargeArea()
+ {
+ AddStep("show", () =>
+ {
+ content.RelativeSizeAxes = Axes.Both;
+ content.Size = new Vector2(1);
+
+ overlay.Show();
+ });
+
+ AddStep("hide", () => overlay.Hide());
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs
similarity index 79%
rename from osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs
rename to osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs
index b0233d35f9..47f5bdfe17 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingAnimation.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLoadingSpinner.cs
@@ -8,12 +8,12 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
- public class TestSceneLoadingAnimation : OsuGridTestScene
+ public class TestSceneLoadingSpinner : OsuGridTestScene
{
- public TestSceneLoadingAnimation()
+ public TestSceneLoadingSpinner()
: base(2, 2)
{
- LoadingAnimation loading;
+ LoadingSpinner loading;
Cell(0).AddRange(new Drawable[]
{
@@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both
},
- loading = new LoadingAnimation()
+ loading = new LoadingSpinner()
});
loading.Show();
@@ -34,7 +34,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Colour = Color4.White,
RelativeSizeAxes = Axes.Both
},
- loading = new LoadingAnimation()
+ loading = new LoadingSpinner(true)
});
loading.Show();
@@ -46,14 +46,14 @@ namespace osu.Game.Tests.Visual.UserInterface
Colour = Color4.Gray,
RelativeSizeAxes = Axes.Both
},
- loading = new LoadingAnimation()
+ loading = new LoadingSpinner()
});
loading.Show();
Cell(3).AddRange(new Drawable[]
{
- loading = new LoadingAnimation()
+ loading = new LoadingSpinner()
});
Scheduler.AddDelayed(() => loading.ToggleVisibility(), 200, true);
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs
new file mode 100644
index 0000000000..02b8839922
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneUserListToolbar.cs
@@ -0,0 +1,57 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Overlays;
+using osu.Game.Overlays.Home.Friends;
+using osuTK;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneUserListToolbar : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(UserSortTabControl),
+ typeof(OverlaySortTabControl<>),
+ typeof(OverlayPanelDisplayStyleControl),
+ typeof(UserListToolbar),
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
+
+ public TestSceneUserListToolbar()
+ {
+ UserListToolbar toolbar;
+ OsuSpriteText sort;
+ OsuSpriteText displayStyle;
+
+ Add(toolbar = new UserListToolbar
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+
+ Add(new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ Children = new Drawable[]
+ {
+ sort = new OsuSpriteText(),
+ displayStyle = new OsuSpriteText()
+ }
+ });
+
+ toolbar.SortCriteria.BindValueChanged(criteria => sort.Text = $"Criteria: {criteria.NewValue}", true);
+ toolbar.DisplayStyle.BindValueChanged(style => displayStyle.Text = $"Style: {style.NewValue}", true);
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs
new file mode 100644
index 0000000000..014cd4663b
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingEditorScreen.cs
@@ -0,0 +1,25 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Game.Tournament.Models;
+using osu.Game.Tournament.Screens.Editors;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneSeedingEditorScreen : LadderTestScene
+ {
+ [Cached]
+ private readonly LadderInfo ladder = new LadderInfo();
+
+ public TestSceneSeedingEditorScreen()
+ {
+ var match = TestSceneSeedingScreen.CreateSampleSeededMatch();
+
+ Add(new SeedingEditorScreen(match.Team1.Value)
+ {
+ Width = 0.85f // create room for control panel
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs
new file mode 100644
index 0000000000..335a6c80a1
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneSeedingScreen.cs
@@ -0,0 +1,127 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Beatmaps;
+using osu.Game.Tournament.Models;
+using osu.Game.Tournament.Screens.TeamIntro;
+using osu.Game.Users;
+
+namespace osu.Game.Tournament.Tests.Screens
+{
+ public class TestSceneSeedingScreen : LadderTestScene
+ {
+ [Cached]
+ private readonly LadderInfo ladder = new LadderInfo();
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ladder.CurrentMatch.Value = CreateSampleSeededMatch();
+
+ Add(new SeedingScreen
+ {
+ FillMode = FillMode.Fit,
+ FillAspectRatio = 16 / 9f
+ });
+ }
+
+ public static TournamentMatch CreateSampleSeededMatch() => new TournamentMatch
+ {
+ Team1 =
+ {
+ Value = new TournamentTeam
+ {
+ FlagName = { Value = "JP" },
+ FullName = { Value = "Japan" },
+ LastYearPlacing = { Value = 10 },
+ Seed = { Value = "Low" },
+ SeedingResults =
+ {
+ new SeedingResult
+ {
+ Mod = { Value = "NM" },
+ Seed = { Value = 10 },
+ Beatmaps =
+ {
+ new SeedingBeatmap
+ {
+ BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
+ Score = 12345672,
+ Seed = { Value = 24 },
+ },
+ new SeedingBeatmap
+ {
+ BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
+ Score = 1234567,
+ Seed = { Value = 12 },
+ },
+ new SeedingBeatmap
+ {
+ BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
+ Score = 1234567,
+ Seed = { Value = 16 },
+ }
+ }
+ },
+ new SeedingResult
+ {
+ Mod = { Value = "DT" },
+ Seed = { Value = 5 },
+ Beatmaps =
+ {
+ new SeedingBeatmap
+ {
+ BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
+ Score = 234567,
+ Seed = { Value = 3 },
+ },
+ new SeedingBeatmap
+ {
+ BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
+ Score = 234567,
+ Seed = { Value = 6 },
+ },
+ new SeedingBeatmap
+ {
+ BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata { Title = "Test Title", Artist = "Test Artist" } },
+ Score = 234567,
+ Seed = { Value = 12 },
+ }
+ }
+ }
+ },
+ Players =
+ {
+ new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 12 } } },
+ new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 16 } } },
+ new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 20 } } },
+ new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 24 } } },
+ new User { Username = "Hello", Statistics = new UserStatistics { Ranks = new UserStatistics.UserRanks { Global = 30 } } },
+ }
+ }
+ },
+ Team2 =
+ {
+ Value = new TournamentTeam
+ {
+ FlagName = { Value = "US" },
+ FullName = { Value = "United States" },
+ Players =
+ {
+ new User { Username = "Hello" },
+ new User { Username = "Hello" },
+ new User { Username = "Hello" },
+ new User { Username = "Hello" },
+ new User { Username = "Hello" },
+ }
+ }
+ },
+ Round =
+ {
+ Value = new TournamentRound { Name = { Value = "Quarterfinals" } }
+ }
+ };
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
index 5cb35a506f..1a2faa76c1 100644
--- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
+++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs
@@ -21,6 +21,7 @@ namespace osu.Game.Tournament.Tests.Screens
match.Team1.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "USA");
match.Team2.Value = Ladder.Teams.FirstOrDefault(t => t.Acronym.Value == "JPN");
match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals");
+ match.Completed.Value = true;
ladder.CurrentMatch.Value = match;
Add(new TeamWinScreen
diff --git a/osu.Game.Tournament/Components/ControlPanel.cs b/osu.Game.Tournament/Components/ControlPanel.cs
index a9bb1bf42f..fa5c941f1a 100644
--- a/osu.Game.Tournament/Components/ControlPanel.cs
+++ b/osu.Game.Tournament/Components/ControlPanel.cs
@@ -5,7 +5,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
@@ -35,7 +34,7 @@ namespace osu.Game.Tournament.Components
RelativeSizeAxes = Axes.Both,
Colour = new Color4(54, 54, 54, 255)
},
- new OsuSpriteText
+ new TournamentSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs
index 361bd92770..99116d4a17 100644
--- a/osu.Game.Tournament/Components/DrawableTournamentTeam.cs
+++ b/osu.Game.Tournament/Components/DrawableTournamentTeam.cs
@@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Models;
namespace osu.Game.Tournament.Components
@@ -19,7 +18,7 @@ namespace osu.Game.Tournament.Components
public readonly TournamentTeam Team;
protected readonly Sprite Flag;
- protected readonly OsuSpriteText AcronymText;
+ protected readonly TournamentSpriteText AcronymText;
[UsedImplicitly]
private Bindable acronym;
@@ -37,9 +36,9 @@ namespace osu.Game.Tournament.Components
FillMode = FillMode.Fit
};
- AcronymText = new OsuSpriteText
+ AcronymText = new TournamentSpriteText
{
- Font = OsuFont.GetFont(weight: FontWeight.Regular),
+ Font = OsuFont.Torus.With(weight: FontWeight.Regular),
};
}
diff --git a/osu.Game.Tournament/Components/SongBar.cs b/osu.Game.Tournament/Components/SongBar.cs
index 8a46da9565..48ea36a8f3 100644
--- a/osu.Game.Tournament/Components/SongBar.cs
+++ b/osu.Game.Tournament/Components/SongBar.cs
@@ -13,7 +13,6 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osu.Game.Screens.Menu;
using osuTK;
@@ -262,7 +261,7 @@ namespace osu.Game.Tournament.Components
static void cp(SpriteText s, Color4 colour)
{
s.Colour = colour;
- s.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 15);
+ s.Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 15);
}
for (var i = 0; i < tuples.Length; i++)
@@ -278,9 +277,9 @@ namespace osu.Game.Tournament.Components
});
}
- AddText(new OsuSpriteText { Text = heading }, s => cp(s, OsuColour.Gray(0.33f)));
+ AddText(new TournamentSpriteText { Text = heading }, s => cp(s, OsuColour.Gray(0.33f)));
AddText(" ", s => cp(s, OsuColour.Gray(0.33f)));
- AddText(new OsuSpriteText { Text = content }, s => cp(s, OsuColour.Gray(0.5f)));
+ AddText(new TournamentSpriteText { Text = content }, s => cp(s, OsuColour.Gray(0.5f)));
}
}
}
diff --git a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
index 51483a0964..394ffe304e 100644
--- a/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
+++ b/osu.Game.Tournament/Components/TournamentBeatmapPanel.cs
@@ -15,7 +15,6 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Models;
using osuTK;
using osuTK.Graphics;
@@ -77,14 +76,14 @@ namespace osu.Game.Tournament.Components
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
- new OsuSpriteText
+ new TournamentSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = new LocalisedString((
$"{Beatmap.Metadata.ArtistUnicode ?? Beatmap.Metadata.Artist} - {Beatmap.Metadata.TitleUnicode ?? Beatmap.Metadata.Title}",
$"{Beatmap.Metadata.Artist} - {Beatmap.Metadata.Title}")),
- Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true),
+ Font = OsuFont.Torus.With(weight: FontWeight.Bold),
},
new FillFlowContainer
{
@@ -95,28 +94,28 @@ namespace osu.Game.Tournament.Components
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = "mapper",
Padding = new MarginPadding { Right = 5 },
- Font = OsuFont.GetFont(italics: true, weight: FontWeight.Regular, size: 14)
+ Font = OsuFont.Torus.With(weight: FontWeight.Regular, size: 14)
},
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = Beatmap.Metadata.AuthorString,
Padding = new MarginPadding { Right = 20 },
- Font = OsuFont.GetFont(italics: true, weight: FontWeight.Bold, size: 14)
+ Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 14)
},
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = "difficulty",
Padding = new MarginPadding { Right = 5 },
- Font = OsuFont.GetFont(italics: true, weight: FontWeight.Regular, size: 14)
+ Font = OsuFont.Torus.With(weight: FontWeight.Regular, size: 14)
},
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = Beatmap.Version,
- Font = OsuFont.GetFont(italics: true, weight: FontWeight.Bold, size: 14)
+ Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 14)
},
}
}
diff --git a/osu.Game.Tournament/Models/SeedingBeatmap.cs b/osu.Game.Tournament/Models/SeedingBeatmap.cs
new file mode 100644
index 0000000000..2cd6fa7188
--- /dev/null
+++ b/osu.Game.Tournament/Models/SeedingBeatmap.cs
@@ -0,0 +1,23 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Bindables;
+using osu.Game.Beatmaps;
+
+namespace osu.Game.Tournament.Models
+{
+ public class SeedingBeatmap
+ {
+ public int ID;
+
+ public BeatmapInfo BeatmapInfo;
+
+ public long Score;
+
+ public Bindable Seed = new BindableInt
+ {
+ MinValue = 1,
+ MaxValue = 64
+ };
+ }
+}
diff --git a/osu.Game.Tournament/Models/SeedingResult.cs b/osu.Game.Tournament/Models/SeedingResult.cs
new file mode 100644
index 0000000000..87aaf8bf36
--- /dev/null
+++ b/osu.Game.Tournament/Models/SeedingResult.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Bindables;
+
+namespace osu.Game.Tournament.Models
+{
+ public class SeedingResult
+ {
+ public List Beatmaps = new List();
+
+ public Bindable Mod = new Bindable();
+
+ public Bindable Seed = new BindableInt
+ {
+ MinValue = 1,
+ MaxValue = 64
+ };
+ }
+}
diff --git a/osu.Game.Tournament/Models/TournamentTeam.cs b/osu.Game.Tournament/Models/TournamentTeam.cs
index 54b8a35180..7fca75cea4 100644
--- a/osu.Game.Tournament/Models/TournamentTeam.cs
+++ b/osu.Game.Tournament/Models/TournamentTeam.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Game.Users;
@@ -29,6 +30,32 @@ namespace osu.Game.Tournament.Models
///
public Bindable Acronym = new Bindable(string.Empty);
+ public BindableList SeedingResults = new BindableList();
+
+ public double AverageRank
+ {
+ get
+ {
+ var ranks = Players.Select(p => p.Statistics?.Ranks.Global)
+ .Where(i => i.HasValue)
+ .Select(i => i.Value)
+ .ToArray();
+
+ if (ranks.Length == 0)
+ return 0;
+
+ return ranks.Average();
+ }
+ }
+
+ public Bindable Seed = new Bindable(string.Empty);
+
+ public Bindable LastYearPlacing = new BindableInt
+ {
+ MinValue = 1,
+ MaxValue = 64
+ };
+
[JsonProperty]
public BindableList Players { get; set; } = new BindableList();
diff --git a/osu.Game.Tournament/Resources/Fonts/Aquatico-Light.bin b/osu.Game.Tournament/Resources/Fonts/Aquatico-Light.bin
deleted file mode 100644
index 42cfdf08de..0000000000
Binary files a/osu.Game.Tournament/Resources/Fonts/Aquatico-Light.bin and /dev/null differ
diff --git a/osu.Game.Tournament/Resources/Fonts/Aquatico-Light_0.png b/osu.Game.Tournament/Resources/Fonts/Aquatico-Light_0.png
deleted file mode 100644
index 332d9ca056..0000000000
Binary files a/osu.Game.Tournament/Resources/Fonts/Aquatico-Light_0.png and /dev/null differ
diff --git a/osu.Game.Tournament/Resources/Fonts/Aquatico-Regular.bin b/osu.Game.Tournament/Resources/Fonts/Aquatico-Regular.bin
deleted file mode 100644
index 3047c2eb3e..0000000000
Binary files a/osu.Game.Tournament/Resources/Fonts/Aquatico-Regular.bin and /dev/null differ
diff --git a/osu.Game.Tournament/Resources/Fonts/Aquatico-Regular_0.png b/osu.Game.Tournament/Resources/Fonts/Aquatico-Regular_0.png
deleted file mode 100644
index 1252d233d3..0000000000
Binary files a/osu.Game.Tournament/Resources/Fonts/Aquatico-Regular_0.png and /dev/null differ
diff --git a/osu.Game.Tournament/Screens/Drawings/Components/Group.cs b/osu.Game.Tournament/Screens/Drawings/Components/Group.cs
index 549ff26018..4126f2db65 100644
--- a/osu.Game.Tournament/Screens/Drawings/Components/Group.cs
+++ b/osu.Game.Tournament/Screens/Drawings/Components/Group.cs
@@ -8,7 +8,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osuTK;
@@ -43,7 +42,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
Colour = new Color4(54, 54, 54, 255)
},
// Group name
- new OsuSpriteText
+ new TournamentSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
@@ -51,7 +50,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
Position = new Vector2(0, 7f),
Text = $"GROUP {name.ToUpperInvariant()}",
- Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 8),
+ Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 8),
Colour = new Color4(255, 204, 34, 255),
},
teams = new FillFlowContainer
@@ -134,7 +133,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
AcronymText.Anchor = Anchor.TopCentre;
AcronymText.Origin = Anchor.TopCentre;
AcronymText.Text = team.Acronym.Value.ToUpperInvariant();
- AcronymText.Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 10);
+ AcronymText.Font = OsuFont.Torus.With(weight: FontWeight.Bold, size: 10);
InternalChildren = new Drawable[]
{
diff --git a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs
index 5efa0a1e69..8be66ff98c 100644
--- a/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs
+++ b/osu.Game.Tournament/Screens/Drawings/DrawingsScreen.cs
@@ -14,7 +14,6 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.Drawings.Components;
@@ -29,7 +28,7 @@ namespace osu.Game.Tournament.Screens.Drawings
private ScrollingTeamContainer teamsContainer;
private GroupContainer groupsContainer;
- private OsuSpriteText fullTeamNameText;
+ private TournamentSpriteText fullTeamNameText;
private readonly List allTeams = new List();
@@ -109,18 +108,18 @@ namespace osu.Game.Tournament.Screens.Drawings
RelativeSizeAxes = Axes.X,
},
// Scrolling team name
- fullTeamNameText = new OsuSpriteText
+ fullTeamNameText = new TournamentSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.TopCentre,
Position = new Vector2(0, 45f),
- Colour = OsuColour.Gray(0.33f),
+ Colour = OsuColour.Gray(0.95f),
Alpha = 0,
- Font = OsuFont.GetFont(weight: FontWeight.Light, size: 42),
+ Font = OsuFont.Torus.With(weight: FontWeight.Light, size: 42),
}
}
},
diff --git a/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs
new file mode 100644
index 0000000000..e68946aaf2
--- /dev/null
+++ b/osu.Game.Tournament/Screens/Editors/SeedingEditorScreen.cs
@@ -0,0 +1,288 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Beatmaps;
+using osu.Game.Graphics;
+using osu.Game.Online.API;
+using osu.Game.Online.API.Requests;
+using osu.Game.Overlays.Settings;
+using osu.Game.Rulesets;
+using osu.Game.Tournament.Components;
+using osu.Game.Tournament.Models;
+using osuTK;
+
+namespace osu.Game.Tournament.Screens.Editors
+{
+ public class SeedingEditorScreen : TournamentEditorScreen
+ {
+ private readonly TournamentTeam team;
+
+ protected override BindableList Storage => team.SeedingResults;
+
+ public SeedingEditorScreen(TournamentTeam team)
+ {
+ this.team = team;
+ }
+
+ public class SeeingResultRow : CompositeDrawable, IModelBacked
+ {
+ public SeedingResult Model { get; }
+
+ [Resolved]
+ private LadderInfo ladderInfo { get; set; }
+
+ public SeeingResultRow(TournamentTeam team, SeedingResult round)
+ {
+ Model = round;
+
+ Masking = true;
+ CornerRadius = 10;
+
+ SeedingBeatmapEditor beatmapEditor = new SeedingBeatmapEditor(round)
+ {
+ Width = 0.95f
+ };
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = OsuColour.Gray(0.1f),
+ RelativeSizeAxes = Axes.Both,
+ },
+ new FillFlowContainer
+ {
+ Margin = new MarginPadding(5),
+ Padding = new MarginPadding { Right = 160 },
+ Spacing = new Vector2(5),
+ Direction = FillDirection.Full,
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
+ {
+ new SettingsTextBox
+ {
+ LabelText = "Mod",
+ Width = 0.33f,
+ Bindable = Model.Mod
+ },
+ new SettingsSlider
+ {
+ LabelText = "Seed",
+ Width = 0.33f,
+ Bindable = Model.Seed
+ },
+ new SettingsButton
+ {
+ Width = 0.2f,
+ Margin = new MarginPadding(10),
+ Text = "Add beatmap",
+ Action = () => beatmapEditor.CreateNew()
+ },
+ beatmapEditor
+ }
+ },
+ new DangerousSettingsButton
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ RelativeSizeAxes = Axes.None,
+ Width = 150,
+ Text = "Delete result",
+ Action = () =>
+ {
+ Expire();
+ team.SeedingResults.Remove(Model);
+ },
+ }
+ };
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ }
+
+ public class SeedingBeatmapEditor : CompositeDrawable
+ {
+ private readonly SeedingResult round;
+ private readonly FillFlowContainer flow;
+
+ public SeedingBeatmapEditor(SeedingResult round)
+ {
+ this.round = round;
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ InternalChild = flow = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ LayoutDuration = 200,
+ LayoutEasing = Easing.OutQuint,
+ ChildrenEnumerable = round.Beatmaps.Select(p => new SeedingBeatmapRow(round, p))
+ };
+ }
+
+ public void CreateNew()
+ {
+ var user = new SeedingBeatmap();
+ round.Beatmaps.Add(user);
+ flow.Add(new SeedingBeatmapRow(round, user));
+ }
+
+ public class SeedingBeatmapRow : CompositeDrawable
+ {
+ private readonly SeedingResult result;
+ public SeedingBeatmap Model { get; }
+
+ [Resolved]
+ protected IAPIProvider API { get; private set; }
+
+ private readonly Bindable beatmapId = new Bindable();
+
+ private readonly Bindable score = new Bindable();
+
+ private readonly Container drawableContainer;
+
+ public SeedingBeatmapRow(SeedingResult result, SeedingBeatmap beatmap)
+ {
+ this.result = result;
+ Model = beatmap;
+
+ Margin = new MarginPadding(10);
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ Masking = true;
+ CornerRadius = 5;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = OsuColour.Gray(0.2f),
+ RelativeSizeAxes = Axes.Both,
+ },
+ new FillFlowContainer
+ {
+ Margin = new MarginPadding(5),
+ Padding = new MarginPadding { Right = 160 },
+ Spacing = new Vector2(5),
+ Direction = FillDirection.Horizontal,
+ AutoSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new SettingsNumberBox
+ {
+ LabelText = "Beatmap ID",
+ RelativeSizeAxes = Axes.None,
+ Width = 200,
+ Bindable = beatmapId,
+ },
+ new SettingsSlider
+ {
+ LabelText = "Seed",
+ RelativeSizeAxes = Axes.None,
+ Width = 200,
+ Bindable = beatmap.Seed
+ },
+ new SettingsTextBox
+ {
+ LabelText = "Score",
+ RelativeSizeAxes = Axes.None,
+ Width = 200,
+ Bindable = score,
+ },
+ drawableContainer = new Container
+ {
+ Size = new Vector2(100, 70),
+ },
+ }
+ },
+ new DangerousSettingsButton
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ RelativeSizeAxes = Axes.None,
+ Width = 150,
+ Text = "Delete Beatmap",
+ Action = () =>
+ {
+ Expire();
+ result.Beatmaps.Remove(beatmap);
+ },
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(RulesetStore rulesets)
+ {
+ beatmapId.Value = Model.ID.ToString();
+ beatmapId.BindValueChanged(idString =>
+ {
+ int parsed;
+
+ int.TryParse(idString.NewValue, out parsed);
+
+ Model.ID = parsed;
+
+ if (idString.NewValue != idString.OldValue)
+ Model.BeatmapInfo = null;
+
+ if (Model.BeatmapInfo != null)
+ {
+ updatePanel();
+ return;
+ }
+
+ var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = Model.ID });
+
+ req.Success += res =>
+ {
+ Model.BeatmapInfo = res.ToBeatmap(rulesets);
+ updatePanel();
+ };
+
+ req.Failure += _ =>
+ {
+ Model.BeatmapInfo = null;
+ updatePanel();
+ };
+
+ API.Queue(req);
+ }, true);
+
+ score.Value = Model.Score.ToString();
+ score.BindValueChanged(str => long.TryParse(str.NewValue, out Model.Score));
+ }
+
+ private void updatePanel()
+ {
+ drawableContainer.Clear();
+
+ if (Model.BeatmapInfo != null)
+ {
+ drawableContainer.Child = new TournamentBeatmapPanel(Model.BeatmapInfo, result.Mod.Value)
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Width = 300
+ };
+ }
+ }
+ }
+ }
+ }
+
+ protected override SeeingResultRow CreateDrawable(SeedingResult model) => new SeeingResultRow(team, model);
+ }
+}
diff --git a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
index 494dd73edd..ca8bce1cca 100644
--- a/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
+++ b/osu.Game.Tournament/Screens/Editors/TeamEditorScreen.cs
@@ -57,6 +57,9 @@ namespace osu.Game.Tournament.Screens.Editors
private readonly Container drawableContainer;
+ [Resolved(canBeNull: true)]
+ private TournamentSceneManager sceneManager { get; set; }
+
[Resolved]
private LadderInfo ladderInfo { get; set; }
@@ -113,6 +116,18 @@ namespace osu.Game.Tournament.Screens.Editors
Width = 0.2f,
Bindable = Model.FlagName
},
+ new SettingsTextBox
+ {
+ LabelText = "Seed",
+ Width = 0.2f,
+ Bindable = Model.Seed
+ },
+ new SettingsSlider
+ {
+ LabelText = "Last Year Placement",
+ Width = 0.33f,
+ Bindable = Model.LastYearPlacing
+ },
new SettingsButton
{
Width = 0.11f,
@@ -131,7 +146,17 @@ namespace osu.Game.Tournament.Screens.Editors
ladderInfo.Teams.Remove(Model);
},
},
- playerEditor
+ playerEditor,
+ new SettingsButton
+ {
+ Width = 0.2f,
+ Margin = new MarginPadding(10),
+ Text = "Edit seeding results",
+ Action = () =>
+ {
+ sceneManager?.SetScreen(new SeedingEditorScreen(team));
+ }
+ },
}
},
};
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs
index 9e1888b44b..ce17c392d0 100644
--- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs
@@ -5,9 +5,9 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
@@ -30,7 +30,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
new TournamentLogo(),
new RoundDisplay
{
- Y = 10,
+ Y = 5,
Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre,
},
@@ -51,9 +51,6 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
{
private readonly TeamColour teamColour;
- private readonly Color4 red = new Color4(129, 68, 65, 255);
- private readonly Color4 blue = new Color4(41, 91, 97, 255);
-
private readonly Bindable currentMatch = new Bindable();
private readonly Bindable currentTeam = new Bindable();
private readonly Bindable currentTeamScore = new Bindable();
@@ -106,7 +103,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
private void teamChanged(TournamentTeam team)
{
- var colour = teamColour == TeamColour.Red ? red : blue;
+ var colour = teamColour == TeamColour.Red ? TournamentGame.COLOUR_RED : TournamentGame.COLOUR_BLUE;
var flip = teamColour != TeamColour.Red;
InternalChildren = new Drawable[]
@@ -169,13 +166,13 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
Children = new Drawable[]
{
Flag,
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = team?.FullName.Value.ToUpper() ?? "???",
X = (flip ? -1 : 1) * 90,
Y = -10,
Colour = colour,
- Font = TournamentFont.GetFont(typeface: TournamentTypeface.Aquatico, weight: FontWeight.Regular, size: 20),
+ Font = OsuFont.Torus.With(weight: FontWeight.Regular, size: 20),
Origin = anchor,
Anchor = anchor,
},
@@ -188,10 +185,31 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
{
private readonly Bindable currentMatch = new Bindable();
+ private readonly TournamentSpriteText text;
+
public RoundDisplay()
{
Width = 200;
Height = 20;
+
+ Masking = true;
+ CornerRadius = 10;
+
+ InternalChildren = new Drawable[]
+ {
+ new Box
+ {
+ Colour = OsuColour.Gray(0.18f),
+ RelativeSizeAxes = Axes.Both,
+ },
+ text = new TournamentSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Colour = Color4.White,
+ Font = OsuFont.Torus.With(weight: FontWeight.Regular, size: 16),
+ },
+ };
}
[BackgroundDependencyLoader]
@@ -201,20 +219,8 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
currentMatch.BindTo(ladder.CurrentMatch);
}
- private void matchChanged(ValueChangedEvent match)
- {
- InternalChildren = new Drawable[]
- {
- new OsuSpriteText
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Colour = Color4.White,
- Text = match.NewValue.Round.Value?.Name.Value ?? "Unknown Round",
- Font = TournamentFont.GetFont(typeface: TournamentTypeface.Aquatico, weight: FontWeight.Regular, size: 18),
- },
- };
- }
+ private void matchChanged(ValueChangedEvent match) =>
+ text.Text = match.NewValue.Round.Value?.Name.Value ?? "Unknown Round";
}
}
}
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs
index cc7903f2fa..fcf1469278 100644
--- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs
@@ -123,8 +123,8 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
public bool Winning
{
set => DisplayedCountSpriteText.Font = value
- ? TournamentFont.GetFont(typeface: TournamentTypeface.Aquatico, weight: FontWeight.Regular, size: 60)
- : TournamentFont.GetFont(typeface: TournamentTypeface.Aquatico, weight: FontWeight.Light, size: 40);
+ ? OsuFont.Torus.With(weight: FontWeight.Regular, size: 60)
+ : OsuFont.Torus.With(weight: FontWeight.Light, size: 40);
}
}
}
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs
index 031d6bf3d2..88d7b95b0c 100644
--- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs
+++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs
@@ -11,7 +11,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
@@ -26,7 +25,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{
private readonly TournamentMatch match;
private readonly bool losers;
- private OsuSpriteText scoreText;
+ private TournamentSpriteText scoreText;
private Box background;
private readonly Bindable score = new Bindable();
@@ -69,7 +68,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
AcronymText.Anchor = AcronymText.Origin = Anchor.CentreLeft;
AcronymText.Padding = new MarginPadding { Left = 50 };
- AcronymText.Font = OsuFont.GetFont(size: 24);
+ AcronymText.Font = OsuFont.Torus.With(size: 24);
if (match != null)
{
@@ -119,11 +118,11 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
Alpha = 0.8f,
RelativeSizeAxes = Axes.Both,
},
- scoreText = new OsuSpriteText
+ scoreText = new TournamentSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Font = OsuFont.GetFont(size: 20),
+ Font = OsuFont.Torus.With(size: 20),
}
}
}
@@ -184,7 +183,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
background.FadeColour(winner ? colourWinner : colourNormal, winner ? 500 : 0, Easing.OutQuint);
- scoreText.Font = AcronymText.Font = OsuFont.GetFont(weight: winner ? FontWeight.Bold : FontWeight.Regular);
+ scoreText.Font = AcronymText.Font = OsuFont.Torus.With(weight: winner ? FontWeight.Bold : FontWeight.Regular);
}
public MenuItem[] ContextMenuItems
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs
index dacd98d3b8..d14ebb4d03 100644
--- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs
+++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableTournamentRound.cs
@@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Models;
using osuTK.Graphics;
@@ -22,8 +21,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
public DrawableTournamentRound(TournamentRound round, bool losers = false)
{
- OsuSpriteText textName;
- OsuSpriteText textDescription;
+ TournamentSpriteText textName;
+ TournamentSpriteText textDescription;
AutoSizeAxes = Axes.Both;
InternalChild = new FillFlowContainer
@@ -32,15 +31,15 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
- textDescription = new OsuSpriteText
+ textDescription = new TournamentSpriteText
{
Colour = Color4.Black,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre
},
- textName = new OsuSpriteText
+ textName = new TournamentSpriteText
{
- Font = OsuFont.GetFont(weight: FontWeight.Bold),
+ Font = OsuFont.Torus.With(weight: FontWeight.Bold),
Colour = Color4.Black,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs
index 8ab083ddaf..4aea7ff4c0 100644
--- a/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs
+++ b/osu.Game.Tournament/Screens/Ladder/Components/LadderEditorSettings.cs
@@ -9,7 +9,6 @@ using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
using osu.Game.Screens.Play.PlayerSettings;
using osu.Game.Tournament.Components;
@@ -126,66 +125,5 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
});
}
}
-
- private class SettingsTeamDropdown : LadderSettingsDropdown
- {
- public SettingsTeamDropdown(BindableList teams)
- {
- foreach (var t in teams.Prepend(new TournamentTeam()))
- add(t);
-
- teams.CollectionChanged += (_, args) =>
- {
- switch (args.Action)
- {
- case NotifyCollectionChangedAction.Add:
- args.NewItems.Cast().ForEach(add);
- break;
-
- case NotifyCollectionChangedAction.Remove:
- args.OldItems.Cast().ForEach(i => Control.RemoveDropdownItem(i));
- break;
- }
- };
- }
-
- private readonly List refBindables = new List();
-
- private T boundReference(T obj)
- where T : IBindable
- {
- obj = (T)obj.GetBoundCopy();
- refBindables.Add(obj);
- return obj;
- }
-
- private void add(TournamentTeam team)
- {
- Control.AddDropdownItem(team);
- boundReference(team.FullName).BindValueChanged(_ =>
- {
- Control.RemoveDropdownItem(team);
- Control.AddDropdownItem(team);
- });
- }
- }
-
- private class LadderSettingsDropdown : SettingsDropdown
- {
- protected override OsuDropdown CreateDropdown() => new DropdownControl();
-
- private new class DropdownControl : SettingsDropdown.DropdownControl
- {
- protected override DropdownMenu CreateMenu() => new Menu();
-
- private new class Menu : OsuDropdownMenu
- {
- public Menu()
- {
- MaxHeight = 200;
- }
- }
- }
- }
}
}
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/LadderSettingsDropdown.cs b/osu.Game.Tournament/Screens/Ladder/Components/LadderSettingsDropdown.cs
new file mode 100644
index 0000000000..347e4d91e0
--- /dev/null
+++ b/osu.Game.Tournament/Screens/Ladder/Components/LadderSettingsDropdown.cs
@@ -0,0 +1,26 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Overlays.Settings;
+
+namespace osu.Game.Tournament.Screens.Ladder.Components
+{
+ public class LadderSettingsDropdown : SettingsDropdown
+ {
+ protected override OsuDropdown CreateDropdown() => new DropdownControl();
+
+ private new class DropdownControl : SettingsDropdown.DropdownControl
+ {
+ protected override DropdownMenu CreateMenu() => new Menu();
+
+ private new class Menu : OsuDropdownMenu
+ {
+ public Menu()
+ {
+ MaxHeight = 200;
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs b/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs
new file mode 100644
index 0000000000..a630e51e44
--- /dev/null
+++ b/osu.Game.Tournament/Screens/Ladder/Components/SettingsTeamDropdown.cs
@@ -0,0 +1,55 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+using osu.Framework.Bindables;
+using osu.Framework.Extensions.IEnumerableExtensions;
+using osu.Game.Tournament.Models;
+
+namespace osu.Game.Tournament.Screens.Ladder.Components
+{
+ public class SettingsTeamDropdown : LadderSettingsDropdown
+ {
+ public SettingsTeamDropdown(BindableList teams)
+ {
+ foreach (var t in teams.Prepend(new TournamentTeam()))
+ add(t);
+
+ teams.CollectionChanged += (_, args) =>
+ {
+ switch (args.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ args.NewItems.Cast().ForEach(add);
+ break;
+
+ case NotifyCollectionChangedAction.Remove:
+ args.OldItems.Cast().ForEach(i => Control.RemoveDropdownItem(i));
+ break;
+ }
+ };
+ }
+
+ private readonly List refBindables = new List();
+
+ private T boundReference(T obj)
+ where T : IBindable
+ {
+ obj = (T)obj.GetBoundCopy();
+ refBindables.Add(obj);
+ return obj;
+ }
+
+ private void add(TournamentTeam team)
+ {
+ Control.AddDropdownItem(team);
+ boundReference(team.FullName).BindValueChanged(_ =>
+ {
+ Control.RemoveDropdownItem(team);
+ Control.AddDropdownItem(team);
+ });
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
index 8ea366e1b4..293f6e0068 100644
--- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
+++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Tournament.Screens.Ladder
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
- new TourneyVideo(storage.GetStream(@"BG Side Logo - OWC.m4v"))
+ new TourneyVideo(storage.GetStream(@"videos/ladder.m4v"))
{
RelativeSizeAxes = Axes.Both,
Loop = true,
@@ -80,7 +80,7 @@ namespace osu.Game.Tournament.Screens.Ladder
break;
case NotifyCollectionChangedAction.Remove:
- foreach (var p in args.NewItems.Cast())
+ foreach (var p in args.OldItems.Cast())
{
foreach (var d in MatchesContainer.Where(d => d.Match == p))
d.Expire();
diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
index c3875716b8..c42d0a6da3 100644
--- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
+++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
@@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
-using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.IPC;
@@ -56,7 +55,7 @@ namespace osu.Game.Tournament.Screens.MapPool
{
Children = new Drawable[]
{
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = "Current Mode"
},
diff --git a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs
index 4b46264055..080570eac4 100644
--- a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs
+++ b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.Ladder.Components;
@@ -34,7 +33,7 @@ namespace osu.Game.Tournament.Screens.Schedule
InternalChildren = new Drawable[]
{
- new TourneyVideo(storage.GetStream(@"BG Side Logo - OWC.m4v"))
+ new TourneyVideo(storage.GetStream(@"videos/schedule.m4v"))
{
RelativeSizeAxes = Axes.Both,
Loop = true,
@@ -107,20 +106,20 @@ namespace osu.Game.Tournament.Screens.Schedule
Height = 0.25f,
Children = new Drawable[]
{
- new OsuSpriteText
+ new TournamentSpriteText
{
Margin = new MarginPadding { Left = -10, Bottom = 10, Top = -5 },
Spacing = new Vector2(10, 0),
Text = match.NewValue.Round.Value?.Name.Value,
Colour = Color4.Black,
- Font = OsuFont.GetFont(size: 20)
+ Font = OsuFont.Torus.With(size: 20)
},
new ScheduleMatch(match.NewValue, false),
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = "Start Time " + match.NewValue.Date.Value.ToUniversalTime().ToString("HH:mm UTC"),
Colour = Color4.Black,
- Font = OsuFont.GetFont(size: 20)
+ Font = OsuFont.Torus.With(size: 20)
},
}
}
@@ -150,7 +149,7 @@ namespace osu.Game.Tournament.Screens.Schedule
Alpha = conditional ? 0.6f : 1,
Margin = new MarginPadding { Horizontal = 10, Vertical = 5 },
});
- AddInternal(new OsuSpriteText
+ AddInternal(new TournamentSpriteText
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomLeft,
@@ -174,13 +173,13 @@ namespace osu.Game.Tournament.Screens.Schedule
Padding = new MarginPadding { Left = 30, Top = 30 };
InternalChildren = new Drawable[]
{
- new OsuSpriteText
+ new TournamentSpriteText
{
X = 30,
Text = title,
Colour = Color4.Black,
Spacing = new Vector2(10, 0),
- Font = OsuFont.GetFont(size: 30)
+ Font = OsuFont.Torus.With(size: 30)
},
content = new FillFlowContainer
{
diff --git a/osu.Game.Tournament/Screens/SetupScreen.cs b/osu.Game.Tournament/Screens/SetupScreen.cs
index 8e1481d87c..023582166c 100644
--- a/osu.Game.Tournament/Screens/SetupScreen.cs
+++ b/osu.Game.Tournament/Screens/SetupScreen.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online.API;
@@ -147,7 +146,7 @@ namespace osu.Game.Tournament.Screens
public Action Action;
- private OsuSpriteText valueText;
+ private TournamentSpriteText valueText;
protected override Drawable CreateComponent() => new Container
{
@@ -155,7 +154,7 @@ namespace osu.Game.Tournament.Screens
RelativeSizeAxes = Axes.X,
Children = new Drawable[]
{
- valueText = new OsuSpriteText
+ valueText = new TournamentSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
diff --git a/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs b/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs
index 20928499bf..d809dfc994 100644
--- a/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs
+++ b/osu.Game.Tournament/Screens/Showcase/ShowcaseScreen.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Tournament.Screens.Showcase
[BackgroundDependencyLoader]
private void load()
{
- AddInternal(new TournamentLogo(false));
+ AddInternal(new TournamentLogo());
}
}
}
diff --git a/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs b/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs
index 1fee2b29e8..6ad5ccaf0c 100644
--- a/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs
+++ b/osu.Game.Tournament/Screens/Showcase/TournamentLogo.cs
@@ -11,20 +11,12 @@ namespace osu.Game.Tournament.Screens.Showcase
{
public class TournamentLogo : CompositeDrawable
{
- public TournamentLogo(bool includeRoundBackground = true)
+ public TournamentLogo()
{
RelativeSizeAxes = Axes.X;
Margin = new MarginPadding { Vertical = 5 };
- if (includeRoundBackground)
- {
- AutoSizeAxes = Axes.Y;
- }
- else
- {
- Masking = true;
- Height = 100;
- }
+ Height = 100;
}
[BackgroundDependencyLoader]
@@ -32,9 +24,11 @@ namespace osu.Game.Tournament.Screens.Showcase
{
InternalChild = new Sprite
{
- Texture = textures.Get("game-screen-logo"),
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
+ FillMode = FillMode.Fit,
+ RelativeSizeAxes = Axes.Both,
+ Texture = textures.Get("game-screen-logo"),
};
}
}
diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs
new file mode 100644
index 0000000000..db5363c155
--- /dev/null
+++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs
@@ -0,0 +1,316 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Framework.Platform;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Tournament.Components;
+using osu.Game.Tournament.Models;
+using osu.Game.Tournament.Screens.Ladder.Components;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Tournament.Screens.TeamIntro
+{
+ public class SeedingScreen : TournamentScreen, IProvideVideo
+ {
+ private Container mainContainer;
+
+ private readonly Bindable currentMatch = new Bindable();
+
+ private readonly Bindable currentTeam = new Bindable();
+
+ [BackgroundDependencyLoader]
+ private void load(Storage storage)
+ {
+ RelativeSizeAxes = Axes.Both;
+
+ InternalChildren = new Drawable[]
+ {
+ new TourneyVideo(storage.GetStream(@"videos/seeding.m4v"))
+ {
+ RelativeSizeAxes = Axes.Both,
+ Loop = true,
+ },
+ mainContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ },
+ new ControlPanel
+ {
+ Children = new Drawable[]
+ {
+ new TourneyButton
+ {
+ RelativeSizeAxes = Axes.X,
+ Text = "Show first team",
+ Action = () => currentTeam.Value = currentMatch.Value.Team1.Value,
+ },
+ new TourneyButton
+ {
+ RelativeSizeAxes = Axes.X,
+ Text = "Show second team",
+ Action = () => currentTeam.Value = currentMatch.Value.Team2.Value,
+ },
+ new SettingsTeamDropdown(LadderInfo.Teams)
+ {
+ LabelText = "Show specific team",
+ Bindable = currentTeam,
+ }
+ }
+ }
+ };
+
+ currentMatch.BindValueChanged(matchChanged);
+ currentMatch.BindTo(LadderInfo.CurrentMatch);
+
+ currentTeam.BindValueChanged(teamChanged, true);
+ }
+
+ private void teamChanged(ValueChangedEvent team)
+ {
+ if (team.NewValue == null)
+ {
+ mainContainer.Clear();
+ return;
+ }
+
+ showTeam(team.NewValue);
+ }
+
+ private void matchChanged(ValueChangedEvent match) =>
+ currentTeam.Value = currentMatch.Value.Team1.Value;
+
+ private void showTeam(TournamentTeam team)
+ {
+ mainContainer.Children = new Drawable[]
+ {
+ new LeftInfo(team) { Position = new Vector2(55, 150), },
+ new RightInfo(team) { Position = new Vector2(500, 150), },
+ };
+ }
+
+ private class RightInfo : CompositeDrawable
+ {
+ public RightInfo(TournamentTeam team)
+ {
+ FillFlowContainer fill;
+
+ Width = 400;
+
+ InternalChildren = new Drawable[]
+ {
+ fill = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ },
+ };
+
+ foreach (var seeding in team.SeedingResults)
+ {
+ fill.Add(new ModRow(seeding.Mod.Value, seeding.Seed.Value));
+ foreach (var beatmap in seeding.Beatmaps)
+ fill.Add(new BeatmapScoreRow(beatmap));
+ }
+ }
+
+ private class BeatmapScoreRow : CompositeDrawable
+ {
+ public BeatmapScoreRow(SeedingBeatmap beatmap)
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+
+ InternalChildren = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(5),
+ Children = new Drawable[]
+ {
+ new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = Color4.Black, },
+ new TournamentSpriteText { Text = "by", Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
+ new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
+ }
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(40),
+ Children = new Drawable[]
+ {
+ new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = Color4.Black, Width = 80 },
+ new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
+ }
+ },
+ };
+ }
+ }
+
+ private class ModRow : CompositeDrawable
+ {
+ private readonly string mods;
+ private readonly int seeding;
+
+ public ModRow(string mods, int seeding)
+ {
+ this.mods = mods;
+ this.seeding = seeding;
+
+ Padding = new MarginPadding { Vertical = 10 };
+
+ AutoSizeAxes = Axes.Y;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(TextureStore textures)
+ {
+ InternalChildren = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(5),
+ Children = new Drawable[]
+ {
+ new Sprite
+ {
+ Texture = textures.Get($"mods/{mods.ToLower()}"),
+ Scale = new Vector2(0.5f)
+ },
+ new Container
+ {
+ Size = new Vector2(50, 16),
+ CornerRadius = 10,
+ Masking = true,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.Black,
+ },
+ new TournamentSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Text = seeding.ToString("#,0"),
+ },
+ }
+ },
+ }
+ },
+ };
+ }
+ }
+ }
+
+ private class LeftInfo : CompositeDrawable
+ {
+ public LeftInfo(TournamentTeam team)
+ {
+ FillFlowContainer fill;
+
+ Width = 200;
+
+ if (team == null) return;
+
+ InternalChildren = new Drawable[]
+ {
+ fill = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ new TeamDisplay(team) { Margin = new MarginPadding { Bottom = 30 } },
+ new RowDisplay("Average Rank:", $"#{team.AverageRank:#,0}"),
+ new RowDisplay("Seed:", team.Seed.Value),
+ new RowDisplay("Last year's placing:", team.LastYearPlacing.Value > 0 ? $"#{team.LastYearPlacing:#,0}" : "0"),
+ new Container { Margin = new MarginPadding { Bottom = 30 } },
+ }
+ },
+ };
+
+ foreach (var p in team.Players)
+ fill.Add(new RowDisplay(p.Username, p.Statistics?.Ranks.Global?.ToString("\\##,0") ?? "-"));
+ }
+
+ internal class RowDisplay : CompositeDrawable
+ {
+ public RowDisplay(string left, string right)
+ {
+ AutoSizeAxes = Axes.Y;
+ RelativeSizeAxes = Axes.X;
+
+ var colour = OsuColour.Gray(0.3f);
+
+ InternalChildren = new Drawable[]
+ {
+ new TournamentSpriteText
+ {
+ Text = left,
+ Colour = colour,
+ Font = OsuFont.Torus.With(size: 22),
+ },
+ new TournamentSpriteText
+ {
+ Text = right,
+ Colour = colour,
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopLeft,
+ Font = OsuFont.Torus.With(size: 22, weight: FontWeight.Regular),
+ },
+ };
+ }
+ }
+
+ private class TeamDisplay : DrawableTournamentTeam
+ {
+ public TeamDisplay(TournamentTeam team)
+ : base(team)
+ {
+ AutoSizeAxes = Axes.Both;
+
+ Flag.RelativeSizeAxes = Axes.None;
+ Flag.Size = new Vector2(300, 200);
+ Flag.Scale = new Vector2(0.3f);
+
+ InternalChild = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(0, 5),
+ Children = new Drawable[]
+ {
+ Flag,
+ new OsuSpriteText
+ {
+ Text = team?.FullName.Value ?? "???",
+ Font = OsuFont.Torus.With(size: 32, weight: FontWeight.SemiBold),
+ Colour = Color4.Black,
+ },
+ }
+ };
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs
index 47c923ff30..6559113f55 100644
--- a/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs
+++ b/osu.Game.Tournament/Screens/TeamIntro/TeamIntroScreen.cs
@@ -7,12 +7,9 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
-using osu.Game.Tournament.Screens.Showcase;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Tournament.Screens.TeamIntro
{
@@ -29,12 +26,11 @@ namespace osu.Game.Tournament.Screens.TeamIntro
InternalChildren = new Drawable[]
{
- new TourneyVideo(storage.GetStream(@"BG Team - Both OWC.m4v"))
+ new TourneyVideo(storage.GetStream(@"videos/teamintro.m4v"))
{
RelativeSizeAxes = Axes.Both,
Loop = true,
},
- new TournamentLogo(false),
mainContainer = new Container
{
RelativeSizeAxes = Axes.Both,
@@ -75,8 +71,9 @@ namespace osu.Game.Tournament.Screens.TeamIntro
{
RelativeSizeAxes = Axes.Both,
Height = 0.25f,
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.BottomCentre,
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Y = 180,
}
};
}
@@ -85,8 +82,6 @@ namespace osu.Game.Tournament.Screens.TeamIntro
{
public RoundDisplay(TournamentMatch match)
{
- var col = OsuColour.Gray(0.33f);
-
InternalChildren = new Drawable[]
{
new FillFlowContainer
@@ -98,31 +93,13 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
- new OsuSpriteText
+ new TournamentSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- Colour = col,
- Text = "COMING UP NEXT",
- Spacing = new Vector2(2, 0),
- Font = OsuFont.GetFont(size: 15, weight: FontWeight.Black)
- },
- new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Colour = col,
+ Colour = OsuColour.Gray(0.33f),
Text = match.Round.Value?.Name.Value ?? "Unknown Round",
- Spacing = new Vector2(10, 0),
- Font = OsuFont.GetFont(size: 50, weight: FontWeight.Light)
- },
- new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Colour = col,
- Text = match.Date.Value.ToUniversalTime().ToString("dd MMMM HH:mm UTC"),
- Font = OsuFont.GetFont(size: 20)
+ Font = OsuFont.Torus.With(size: 26, weight: FontWeight.Light)
},
}
}
@@ -132,21 +109,19 @@ namespace osu.Game.Tournament.Screens.TeamIntro
private class TeamWithPlayers : CompositeDrawable
{
- private readonly Color4 red = new Color4(129, 68, 65, 255);
- private readonly Color4 blue = new Color4(41, 91, 97, 255);
-
public TeamWithPlayers(TournamentTeam team, bool left = false)
{
FillFlowContainer players;
- var colour = left ? red : blue;
+ var colour = left ? TournamentGame.COLOUR_RED : TournamentGame.COLOUR_BLUE;
InternalChildren = new Drawable[]
{
- new TeamDisplay(team, left ? "Team Red" : "Team Blue", colour)
+ new TeamDisplay(team)
{
Anchor = left ? Anchor.CentreRight : Anchor.CentreLeft,
- Origin = Anchor.Centre,
+ Origin = Anchor.TopCentre,
RelativePositionAxes = Axes.Both,
- X = (left ? -1 : 1) * 0.36f,
+ X = (left ? -1 : 1) * 0.3145f,
+ Y = -0.077f,
},
players = new FillFlowContainer
{
@@ -157,7 +132,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Anchor = left ? Anchor.CentreRight : Anchor.CentreLeft,
Origin = left ? Anchor.CentreRight : Anchor.CentreLeft,
RelativePositionAxes = Axes.Both,
- X = (left ? -1 : 1) * 0.66f,
+ X = (left ? -1 : 1) * 0.58f,
},
};
@@ -165,10 +140,10 @@ namespace osu.Game.Tournament.Screens.TeamIntro
{
foreach (var p in team.Players)
{
- players.Add(new OsuSpriteText
+ players.Add(new TournamentSpriteText
{
Text = p.Username,
- Font = OsuFont.GetFont(size: 24),
+ Font = OsuFont.Torus.With(size: 24),
Colour = colour,
Anchor = left ? Anchor.CentreRight : Anchor.CentreLeft,
Origin = left ? Anchor.CentreRight : Anchor.CentreLeft,
@@ -179,7 +154,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
private class TeamDisplay : DrawableTournamentTeam
{
- public TeamDisplay(TournamentTeam team, string teamName, Color4 colour)
+ public TeamDisplay(TournamentTeam team)
: base(team)
{
AutoSizeAxes = Axes.Both;
@@ -187,33 +162,24 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Flag.Anchor = Flag.Origin = Anchor.TopCentre;
Flag.RelativeSizeAxes = Axes.None;
Flag.Size = new Vector2(300, 200);
- Flag.Scale = new Vector2(0.4f);
- Flag.Margin = new MarginPadding { Bottom = 20 };
+ Flag.Scale = new Vector2(0.32f);
InternalChild = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 5),
+ Spacing = new Vector2(160),
Children = new Drawable[]
{
Flag,
- new OsuSpriteText
+ new TournamentSpriteText
{
- Text = team?.FullName.Value.ToUpper() ?? "???",
- Font = TournamentFont.GetFont(TournamentTypeface.Aquatico, 40, FontWeight.Light),
- Colour = Color4.Black,
+ Text = team?.FullName.Value ?? "???",
+ Font = OsuFont.Torus.With(size: 20, weight: FontWeight.Regular),
+ Colour = OsuColour.Gray(0.2f),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
},
- new OsuSpriteText
- {
- Text = teamName.ToUpper(),
- Font = TournamentFont.GetFont(TournamentTypeface.Aquatico, 20, FontWeight.Regular),
- Colour = colour,
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- }
}
};
}
diff --git a/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs b/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs
index a0216c5db3..30b86f8421 100644
--- a/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs
+++ b/osu.Game.Tournament/Screens/TeamWin/TeamWinScreen.cs
@@ -7,10 +7,8 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
-using osu.Game.Tournament.Screens.Showcase;
using osuTK;
using osuTK.Graphics;
@@ -33,22 +31,18 @@ namespace osu.Game.Tournament.Screens.TeamWin
InternalChildren = new Drawable[]
{
- blueWinVideo = new TourneyVideo(storage.GetStream(@"BG Team - Win Blue.m4v"))
+ blueWinVideo = new TourneyVideo(storage.GetStream(@"videos/teamwin-blue.m4v"))
{
Alpha = 1,
RelativeSizeAxes = Axes.Both,
Loop = true,
},
- redWinVideo = new TourneyVideo(storage.GetStream(@"BG Team - Win Red.m4v"))
+ redWinVideo = new TourneyVideo(storage.GetStream(@"videos/teamwin-red.m4v"))
{
Alpha = 0,
RelativeSizeAxes = Axes.Both,
Loop = true,
},
- new TournamentLogo(false)
- {
- Y = 40,
- },
mainContainer = new Container
{
RelativeSizeAxes = Axes.Both,
@@ -85,141 +79,99 @@ namespace osu.Game.Tournament.Screens.TeamWin
mainContainer.Children = new Drawable[]
{
+ new TeamFlagDisplay(match.Winner)
+ {
+ Size = new Vector2(300, 200),
+ Scale = new Vector2(0.5f),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ X = -387,
+ },
+ new TournamentSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.TopLeft,
+ Position = new Vector2(78, -70),
+ Colour = OsuColour.Gray(0.33f),
+ Text = match.Round.Value?.Name.Value ?? "Unknown Round",
+ Font = OsuFont.Torus.With(size: 30, weight: FontWeight.Regular)
+ },
new TeamWithPlayers(match.Winner, redWin)
{
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
Height = 0.6f,
Anchor = Anchor.Centre,
- Origin = Anchor.Centre
+ Origin = Anchor.TopLeft,
+ Position = new Vector2(78, 0),
},
- new RoundDisplay(match)
- {
- RelativeSizeAxes = Axes.Both,
- Height = 0.25f,
- Anchor = Anchor.BottomCentre,
- Origin = Anchor.BottomCentre,
- }
};
}
- private class RoundDisplay : CompositeDrawable
- {
- public RoundDisplay(TournamentMatch match)
- {
- var col = OsuColour.Gray(0.33f);
-
- InternalChildren = new Drawable[]
- {
- new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 10),
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Colour = col,
- Text = "WINNER",
- Font = TournamentFont.GetFont(TournamentTypeface.Aquatico, 15, FontWeight.Regular),
- },
- new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Colour = col,
- Text = match.Round.Value?.Name.Value ?? "Unknown Round",
- Font = TournamentFont.GetFont(TournamentTypeface.Aquatico, 50, FontWeight.Light),
- Spacing = new Vector2(10, 0),
- },
- new OsuSpriteText
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Colour = col,
- Text = match.Date.Value.ToUniversalTime().ToString("dd MMMM HH:mm UTC"),
- Font = TournamentFont.GetFont(TournamentTypeface.Aquatico, 20, FontWeight.Light),
- },
- }
- }
- };
- }
- }
-
private class TeamWithPlayers : CompositeDrawable
{
- private readonly Color4 red = new Color4(129, 68, 65, 255);
- private readonly Color4 blue = new Color4(41, 91, 97, 255);
-
public TeamWithPlayers(TournamentTeam team, bool left = false)
{
- var colour = left ? red : blue;
+ FillFlowContainer players;
+
+ var colour = left ? TournamentGame.COLOUR_RED : TournamentGame.COLOUR_BLUE;
InternalChildren = new Drawable[]
{
- new TeamDisplay(team, left ? "Team Red" : "Team Blue", colour)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- },
new FillFlowContainer
{
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Both,
- Spacing = new Vector2(0, 5),
- Padding = new MarginPadding(20),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.Both,
- },
- };
- }
-
- private class TeamDisplay : DrawableTournamentTeam
- {
- public TeamDisplay(TournamentTeam team, string teamName, Color4 colour)
- : base(team)
- {
- AutoSizeAxes = Axes.Both;
-
- Flag.Anchor = Flag.Origin = Anchor.TopCentre;
- Flag.RelativeSizeAxes = Axes.None;
- Flag.Size = new Vector2(300, 200);
- Flag.Scale = new Vector2(0.4f);
- Flag.Margin = new MarginPadding { Bottom = 20 };
-
- InternalChild = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 5),
Children = new Drawable[]
{
- Flag,
- new OsuSpriteText
+ new TournamentSpriteText
{
- Text = team?.FullName.Value.ToUpper() ?? "???",
- Font = TournamentFont.GetFont(TournamentTypeface.Aquatico, 40, FontWeight.Light),
+ Text = "WINNER",
+ Font = OsuFont.Torus.With(size: 24, weight: FontWeight.SemiBold),
Colour = Color4.Black,
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
},
- new OsuSpriteText
+ new TournamentSpriteText
{
- Text = teamName.ToUpper(),
- Font = OsuFont.GetFont(size: 20),
- Colour = colour,
- Origin = Anchor.TopCentre,
- Anchor = Anchor.TopCentre,
- }
+ Text = team?.FullName.Value ?? "???",
+ Font = OsuFont.Torus.With(size: 30, weight: FontWeight.SemiBold),
+ Colour = Color4.Black,
+ },
+ players = new FillFlowContainer
+ {
+ Direction = FillDirection.Vertical,
+ AutoSizeAxes = Axes.Both,
+ Padding = new MarginPadding { Top = 10 },
+ },
}
- };
+ },
+ };
+
+ if (team != null)
+ {
+ foreach (var p in team.Players)
+ {
+ players.Add(new TournamentSpriteText
+ {
+ Text = p.Username,
+ Font = OsuFont.Torus.With(size: 24),
+ Colour = colour,
+ Anchor = left ? Anchor.CentreRight : Anchor.CentreLeft,
+ Origin = left ? Anchor.CentreRight : Anchor.CentreLeft,
+ });
+ }
}
}
}
+
+ private class TeamFlagDisplay : DrawableTournamentTeam
+ {
+ public TeamFlagDisplay(TournamentTeam team)
+ : base(team)
+ {
+ InternalChildren = new Drawable[]
+ {
+ Flag
+ };
+ }
+ }
}
}
diff --git a/osu.Game.Tournament/TournamentFont.cs b/osu.Game.Tournament/TournamentFont.cs
deleted file mode 100644
index 32f0264562..0000000000
--- a/osu.Game.Tournament/TournamentFont.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics;
-
-namespace osu.Game.Tournament
-{
- public static class TournamentFont
- {
- ///
- /// The default font size.
- ///
- public const float DEFAULT_FONT_SIZE = 16;
-
- ///
- /// Retrieves a .
- ///
- /// The font typeface.
- /// The size of the text in local space. For a value of 16, a single line will have a height of 16px.
- /// The font weight.
- /// Whether the font is italic.
- /// Whether all characters should be spaced the same distance apart.
- /// The .
- public static FontUsage GetFont(TournamentTypeface typeface = TournamentTypeface.Aquatico, float size = DEFAULT_FONT_SIZE, FontWeight weight = FontWeight.Medium, bool italics = false, bool fixedWidth = false)
- => new FontUsage(GetFamilyString(typeface), size, GetWeightString(typeface, weight), italics, fixedWidth);
-
- ///
- /// Retrieves the string representation of a .
- ///
- /// The .
- /// The string representation.
- public static string GetFamilyString(TournamentTypeface typeface)
- {
- switch (typeface)
- {
- case TournamentTypeface.Aquatico:
- return "Aquatico";
- }
-
- return null;
- }
-
- ///
- /// Retrieves the string representation of a .
- ///
- /// The .
- /// The .
- /// The string representation of in the specified .
- public static string GetWeightString(TournamentTypeface typeface, FontWeight weight)
- => GetWeightString(GetFamilyString(typeface), weight);
-
- ///
- /// Retrieves the string representation of a .
- ///
- /// The family string.
- /// The .
- /// The string representation of in the specified .
- public static string GetWeightString(string family, FontWeight weight)
- {
- string weightString = weight.ToString();
-
- // Only exo has an explicit "regular" weight, other fonts do not
- if (weight == FontWeight.Regular && family != GetFamilyString(TournamentTypeface.Aquatico))
- weightString = string.Empty;
-
- return weightString;
- }
- }
-
- public enum TournamentTypeface
- {
- Aquatico
- }
-}
diff --git a/osu.Game.Tournament/TournamentGame.cs b/osu.Game.Tournament/TournamentGame.cs
index 7dbcf37af6..608fc5f04a 100644
--- a/osu.Game.Tournament/TournamentGame.cs
+++ b/osu.Game.Tournament/TournamentGame.cs
@@ -3,11 +3,15 @@
using osu.Framework.Graphics;
using osu.Game.Graphics.Cursor;
+using osuTK.Graphics;
namespace osu.Game.Tournament
{
public class TournamentGame : TournamentGameBase
{
+ public static readonly Color4 COLOUR_RED = new Color4(144, 0, 0, 255);
+ public static readonly Color4 COLOUR_BLUE = new Color4(0, 84, 144, 255);
+
protected override void LoadComplete()
{
base.LoadComplete();
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index 1c94856a4e..435f315c8d 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -18,7 +18,6 @@ using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models;
@@ -54,9 +53,6 @@ namespace osu.Game.Tournament
{
Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));
- AddFont(Resources, @"Resources/Fonts/Aquatico-Regular");
- AddFont(Resources, @"Resources/Fonts/Aquatico-Light");
-
Textures.AddStore(new TextureLoaderStore(new ResourceStore(new StorageBackedResourceStore(storage))));
this.storage = storage;
@@ -104,10 +100,10 @@ namespace osu.Game.Tournament
Colour = Color4.Red,
RelativeSizeAxes = Axes.Both,
},
- new OsuSpriteText
+ new TournamentSpriteText
{
Text = "Please make the window wider",
- Font = OsuFont.Default.With(weight: "bold"),
+ Font = OsuFont.Torus.With(weight: FontWeight.Bold),
Colour = Color4.White,
Padding = new MarginPadding(20)
}
@@ -124,10 +120,9 @@ namespace osu.Game.Tournament
using (var sr = new StreamReader(stream))
ladder = JsonConvert.DeserializeObject(sr.ReadToEnd());
}
- else
- {
+
+ if (ladder == null)
ladder = new LadderInfo();
- }
if (ladder.Ruleset.Value == null)
ladder.Ruleset.Value = RulesetStore.AvailableRulesets.First();
@@ -205,9 +200,11 @@ namespace osu.Game.Tournament
{
foreach (var p in t.Players)
{
- if (p.Username == null || p.Statistics == null)
+ if (string.IsNullOrEmpty(p.Username) || p.Statistics == null)
+ {
PopulateUser(p);
- addedInfo = true;
+ addedInfo = true;
+ }
}
}
@@ -243,6 +240,24 @@ namespace osu.Game.Tournament
}
}
+ foreach (var t in ladder.Teams)
+ {
+ foreach (var s in t.SeedingResults)
+ {
+ foreach (var b in s.Beatmaps)
+ {
+ if (b.BeatmapInfo == null && b.ID > 0)
+ {
+ var req = new GetBeatmapRequest(new BeatmapInfo { OnlineBeatmapID = b.ID });
+ req.Perform(API);
+ b.BeatmapInfo = req.Result?.ToBeatmap(RulesetStore);
+
+ addedInfo = true;
+ }
+ }
+ }
+ }
+
return addedInfo;
}
diff --git a/osu.Game.Tournament/TournamentSceneManager.cs b/osu.Game.Tournament/TournamentSceneManager.cs
index de3d685c31..9f5f2b6827 100644
--- a/osu.Game.Tournament/TournamentSceneManager.cs
+++ b/osu.Game.Tournament/TournamentSceneManager.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Tournament
//Masking = true,
Children = new Drawable[]
{
- video = new TourneyVideo(storage.GetStream("BG Logoless - OWC.m4v"))
+ video = new TourneyVideo(storage.GetStream("videos/main.m4v"))
{
Loop = true,
RelativeSizeAxes = Axes.Both,
@@ -80,6 +80,7 @@ namespace osu.Game.Tournament
new ShowcaseScreen(),
new MapPoolScreen(),
new TeamIntroScreen(),
+ new SeedingScreen(),
new DrawingsScreen(),
new GameplayScreen(),
new TeamWinScreen()
@@ -121,6 +122,7 @@ namespace osu.Game.Tournament
new ScreenButton(typeof(LadderScreen)) { Text = "Bracket", RequestSelection = SetScreen },
new Separator(),
new ScreenButton(typeof(TeamIntroScreen)) { Text = "TeamIntro", RequestSelection = SetScreen },
+ new ScreenButton(typeof(SeedingScreen)) { Text = "Seeding", RequestSelection = SetScreen },
new Separator(),
new ScreenButton(typeof(MapPoolScreen)) { Text = "MapPool", RequestSelection = SetScreen },
new ScreenButton(typeof(GameplayScreen)) { Text = "Gameplay", RequestSelection = SetScreen },
@@ -146,8 +148,20 @@ namespace osu.Game.Tournament
private Drawable currentScreen;
private ScheduledDelegate scheduledHide;
+ private Drawable temporaryScreen;
+
+ public void SetScreen(Drawable screen)
+ {
+ currentScreen?.Hide();
+ currentScreen = null;
+
+ screens.Add(temporaryScreen = screen);
+ }
+
public void SetScreen(Type screenType)
{
+ temporaryScreen?.Expire();
+
var target = screens.FirstOrDefault(s => s.GetType() == screenType);
if (target == null || currentScreen == target) return;
diff --git a/osu.Game.Tournament/TournamentSpriteText.cs b/osu.Game.Tournament/TournamentSpriteText.cs
new file mode 100644
index 0000000000..e550dfbfae
--- /dev/null
+++ b/osu.Game.Tournament/TournamentSpriteText.cs
@@ -0,0 +1,16 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Tournament
+{
+ public class TournamentSpriteText : OsuSpriteText
+ {
+ public TournamentSpriteText()
+ {
+ Font = OsuFont.Torus;
+ }
+ }
+}
diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
index 30346a8a96..eb05cbaf85 100644
--- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
+++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapBackgroundSprite.cs
@@ -16,6 +16,8 @@ namespace osu.Game.Beatmaps.Drawables
{
public readonly Bindable Beatmap = new Bindable();
+ protected override double LoadDelay => 500;
+
[Resolved]
private BeatmapManager beatmaps { get; set; }
diff --git a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs
index 16eecb7198..c60bd0286e 100644
--- a/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs
+++ b/osu.Game/Beatmaps/Drawables/UpdateableBeatmapSetCover.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
@@ -50,7 +49,7 @@ namespace osu.Game.Beatmaps.Drawables
Child = new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.1f)),
+ Colour = OsuColour.Gray(0.2f),
};
}
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index ce959e9057..21de654670 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Configuration.Tracking;
using osu.Framework.Extensions;
@@ -126,6 +127,35 @@ namespace osu.Game.Configuration
public OsuConfigManager(Storage storage)
: base(storage)
{
+ Migrate();
+ }
+
+ public void Migrate()
+ {
+ // arrives as 2020.123.0
+ var rawVersion = Get(OsuSetting.Version);
+
+ if (rawVersion.Length < 6)
+ return;
+
+ var pieces = rawVersion.Split('.');
+
+ // on a fresh install or when coming from a non-release build, execution will end here.
+ // we don't want to run migrations in such cases.
+ if (!int.TryParse(pieces[0], out int year)) return;
+ if (!int.TryParse(pieces[1], out int monthDay)) return;
+
+ int combined = (year * 10000) + monthDay;
+
+ if (combined < 20200305)
+ {
+ // the maximum value of this setting was changed.
+ // if we don't manually increase this, it causes song select to filter out beatmaps the user expects to see.
+ var maxStars = (BindableDouble)GetOriginalBindable(OsuSetting.DisplayStarsMaximum);
+
+ if (maxStars.Value == 10)
+ maxStars.Value = maxStars.MaxValue;
+ }
}
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs
index 4bdbb5fc24..fe487cb1d0 100644
--- a/osu.Game/Configuration/SettingSourceAttribute.cs
+++ b/osu.Game/Configuration/SettingSourceAttribute.cs
@@ -8,7 +8,6 @@ using System.Reflection;
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.UserInterface;
using osu.Game.Overlays.Settings;
namespace osu.Game.Configuration
@@ -105,7 +104,8 @@ namespace osu.Game.Configuration
var dropdownType = typeof(SettingsEnumDropdown<>).MakeGenericType(bindable.GetType().GetGenericArguments()[0]);
var dropdown = (Drawable)Activator.CreateInstance(dropdownType);
- dropdown.GetType().GetProperty(nameof(IHasCurrentValue
public static FontUsage Default => GetFont();
- public static FontUsage Numeric => GetFont(Typeface.Venera, weight: FontWeight.Regular);
+ public static FontUsage Numeric => GetFont(Typeface.Venera, weight: FontWeight.Bold);
+
+ public static FontUsage Torus => GetFont(Typeface.Torus, weight: FontWeight.Regular);
///
/// Retrieves a .
@@ -45,6 +47,9 @@ namespace osu.Game.Graphics
case Typeface.Venera:
return "Venera";
+
+ case Typeface.Torus:
+ return "Torus";
}
return null;
@@ -65,16 +70,7 @@ namespace osu.Game.Graphics
/// The family string.
/// The .
/// The string representation of in the specified .
- public static string GetWeightString(string family, FontWeight weight)
- {
- string weightString = weight.ToString();
-
- // Only exo has an explicit "regular" weight, other fonts do not
- if (family != GetFamilyString(Typeface.Exo) && weight == FontWeight.Regular)
- weightString = string.Empty;
-
- return weightString;
- }
+ public static string GetWeightString(string family, FontWeight weight) => weight.ToString();
}
public static class OsuFontExtensions
@@ -102,15 +98,39 @@ namespace osu.Game.Graphics
{
Exo,
Venera,
+ Torus
}
public enum FontWeight
{
- Light,
- Regular,
- Medium,
- SemiBold,
- Bold,
- Black
+ ///
+ /// Equivalent to weight 300.
+ ///
+ Light = 300,
+
+ ///
+ /// Equivalent to weight 400.
+ ///
+ Regular = 400,
+
+ ///
+ /// Equivalent to weight 500.
+ ///
+ Medium = 500,
+
+ ///
+ /// Equivalent to weight 600.
+ ///
+ SemiBold = 600,
+
+ ///
+ /// Equivalent to weight 700.
+ ///
+ Bold = 700,
+
+ ///
+ /// Equivalent to weight 900.
+ ///
+ Black = 900
}
}
diff --git a/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs b/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs
deleted file mode 100644
index bdc3cd4c49..0000000000
--- a/osu.Game/Graphics/UserInterface/DimmedLoadingLayer.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osuTK.Graphics;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Extensions.Color4Extensions;
-using osuTK;
-using osu.Framework.Input.Events;
-
-namespace osu.Game.Graphics.UserInterface
-{
- public class DimmedLoadingLayer : OverlayContainer
- {
- private const float transition_duration = 250;
-
- private readonly LoadingAnimation loading;
-
- public DimmedLoadingLayer(float dimAmount = 0.5f, float iconScale = 1f)
- {
- RelativeSizeAxes = Axes.Both;
- Children = new Drawable[]
- {
- new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black.Opacity(dimAmount),
- },
- loading = new LoadingAnimation { Scale = new Vector2(iconScale) },
- };
- }
-
- protected override void PopIn()
- {
- this.FadeIn(transition_duration, Easing.OutQuint);
- loading.Show();
- }
-
- protected override void PopOut()
- {
- this.FadeOut(transition_duration, Easing.OutQuint);
- loading.Hide();
- }
-
- protected override bool Handle(UIEvent e)
- {
- switch (e)
- {
- // blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer.
- case ScrollEvent _:
- return false;
- }
-
- return base.Handle(e);
- }
- }
-}
diff --git a/osu.Game/Graphics/UserInterface/ExpandingBar.cs b/osu.Game/Graphics/UserInterface/ExpandingBar.cs
index 439a6002d8..60cb35b4c4 100644
--- a/osu.Game/Graphics/UserInterface/ExpandingBar.cs
+++ b/osu.Game/Graphics/UserInterface/ExpandingBar.cs
@@ -13,17 +13,17 @@ namespace osu.Game.Graphics.UserInterface
///
public class ExpandingBar : Circle
{
- private bool isCollapsed;
+ private bool expanded = true;
- public bool IsCollapsed
+ public bool Expanded
{
- get => isCollapsed;
+ get => expanded;
set
{
- if (value == isCollapsed)
+ if (value == expanded)
return;
- isCollapsed = value;
+ expanded = value;
updateState();
}
}
@@ -83,19 +83,21 @@ namespace osu.Game.Graphics.UserInterface
updateState();
}
- public void Collapse() => IsCollapsed = true;
+ public void Collapse() => Expanded = false;
- public void Expand() => IsCollapsed = false;
+ public void Expand() => Expanded = true;
private void updateState()
{
- float newSize = IsCollapsed ? CollapsedSize : ExpandedSize;
- Easing easingType = IsCollapsed ? Easing.Out : Easing.OutElastic;
+ float newSize = expanded ? ExpandedSize : CollapsedSize;
+ Easing easingType = expanded ? Easing.OutElastic : Easing.Out;
if (RelativeSizeAxes == Axes.X)
this.ResizeHeightTo(newSize, 400, easingType);
else
this.ResizeWidthTo(newSize, 400, easingType);
+
+ this.FadeTo(expanded ? 1 : 0.5f, 100, Easing.OutQuint);
}
}
}
diff --git a/osu.Game/Graphics/UserInterface/LineGraph.cs b/osu.Game/Graphics/UserInterface/LineGraph.cs
index 6d65b77cbf..42b523fc5c 100644
--- a/osu.Game/Graphics/UserInterface/LineGraph.cs
+++ b/osu.Game/Graphics/UserInterface/LineGraph.cs
@@ -4,11 +4,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using osu.Framework.Caching;
using osuTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
+using osu.Framework.Layout;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterface
@@ -83,17 +83,11 @@ namespace osu.Game.Graphics.UserInterface
PathRadius = 1
}
});
+
+ AddLayout(pathCached);
}
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & Invalidation.DrawSize) > 0)
- pathCached.Invalidate();
-
- return base.Invalidate(invalidation, source, shallPropagate);
- }
-
- private readonly Cached pathCached = new Cached();
+ private readonly LayoutValue pathCached = new LayoutValue(Invalidation.DrawSize);
protected override void Update()
{
diff --git a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
deleted file mode 100644
index 5a8a0da135..0000000000
--- a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osuTK;
-using osuTK.Graphics;
-
-namespace osu.Game.Graphics.UserInterface
-{
- ///
- /// A loading spinner.
- ///
- public class LoadingAnimation : VisibilityContainer
- {
- private readonly SpriteIcon spinner;
- private readonly SpriteIcon spinnerShadow;
-
- private const float spin_duration = 600;
- private const float transition_duration = 200;
-
- public LoadingAnimation()
- {
- Size = new Vector2(20);
-
- Anchor = Anchor.Centre;
- Origin = Anchor.Centre;
-
- Children = new Drawable[]
- {
- spinnerShadow = new SpriteIcon
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Position = new Vector2(1, 1),
- Colour = Color4.Black,
- Alpha = 0.4f,
- Icon = FontAwesome.Solid.CircleNotch
- },
- spinner = new SpriteIcon
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Icon = FontAwesome.Solid.CircleNotch
- }
- };
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- spinner.Spin(spin_duration, RotationDirection.Clockwise);
- spinnerShadow.Spin(spin_duration, RotationDirection.Clockwise);
- }
-
- protected override void PopIn() => this.FadeIn(transition_duration * 2, Easing.OutQuint);
-
- protected override void PopOut() => this.FadeOut(transition_duration, Easing.OutQuint);
- }
-}
diff --git a/osu.Game/Graphics/UserInterface/LoadingButton.cs b/osu.Game/Graphics/UserInterface/LoadingButton.cs
index 49ec18ce8e..81dc023d7e 100644
--- a/osu.Game/Graphics/UserInterface/LoadingButton.cs
+++ b/osu.Game/Graphics/UserInterface/LoadingButton.cs
@@ -40,14 +40,14 @@ namespace osu.Game.Graphics.UserInterface
set => loading.Size = value;
}
- private readonly LoadingAnimation loading;
+ private readonly LoadingSpinner loading;
protected LoadingButton()
{
AddRange(new[]
{
CreateContent(),
- loading = new LoadingAnimation
+ loading = new LoadingSpinner
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
diff --git a/osu.Game/Graphics/UserInterface/LoadingLayer.cs b/osu.Game/Graphics/UserInterface/LoadingLayer.cs
new file mode 100644
index 0000000000..35b33c3d03
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/LoadingLayer.cs
@@ -0,0 +1,81 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Input.Events;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ ///
+ /// A layer that will show a loading spinner and completely block input to an area.
+ /// Also optionally dims target elements.
+ /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance.
+ ///
+ public class LoadingLayer : LoadingSpinner
+ {
+ private readonly Drawable dimTarget;
+
+ ///
+ /// Constuct a new loading spinner.
+ ///
+ /// An optional target to dim when displayed.
+ /// Whether the spinner should have a surrounding black box for visibility.
+ public LoadingLayer(Drawable dimTarget = null, bool withBox = true)
+ : base(withBox)
+ {
+ RelativeSizeAxes = Axes.Both;
+ Size = new Vector2(1);
+
+ this.dimTarget = dimTarget;
+
+ MainContents.RelativeSizeAxes = Axes.None;
+ }
+
+ public override bool HandleNonPositionalInput => false;
+
+ protected override bool Handle(UIEvent e)
+ {
+ switch (e)
+ {
+ // blocking scroll can cause weird behaviour when this layer is used within a ScrollContainer.
+ case ScrollEvent _:
+ return false;
+ }
+
+ return true;
+ }
+
+ protected override void PopIn()
+ {
+ dimTarget?.FadeColour(OsuColour.Gray(0.5f), TRANSITION_DURATION, Easing.OutQuint);
+ base.PopIn();
+ }
+
+ protected override void PopOut()
+ {
+ dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
+ base.PopOut();
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+ MainContents.Size = new Vector2(Math.Clamp(Math.Min(DrawWidth, DrawHeight) * 0.25f, 30, 100));
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+
+ if (State.Value == Visibility.Visible)
+ {
+ // ensure we don't leave the target in a bad state.
+ dimTarget?.FadeColour(Color4.White, TRANSITION_DURATION, Easing.OutQuint);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/LoadingSpinner.cs b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs
new file mode 100644
index 0000000000..36d429b8c1
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/LoadingSpinner.cs
@@ -0,0 +1,106 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Graphics.UserInterface
+{
+ ///
+ /// A loading spinner.
+ ///
+ public class LoadingSpinner : VisibilityContainer
+ {
+ private readonly SpriteIcon spinner;
+
+ protected Container MainContents;
+
+ protected const float TRANSITION_DURATION = 500;
+
+ private const float spin_duration = 900;
+
+ ///
+ /// Constuct a new loading spinner.
+ ///
+ /// Whether the spinner should have a surrounding black box for visibility.
+ public LoadingSpinner(bool withBox = false)
+ {
+ Size = new Vector2(60);
+
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Child = MainContents = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ CornerRadius = 20,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ Colour = Color4.Black,
+ RelativeSizeAxes = Axes.Both,
+ Alpha = withBox ? 0.7f : 0
+ },
+ spinner = new SpriteIcon
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Scale = new Vector2(withBox ? 0.6f : 1),
+ RelativeSizeAxes = Axes.Both,
+ Icon = FontAwesome.Solid.CircleNotch
+ }
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ rotate();
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ MainContents.CornerRadius = MainContents.DrawWidth / 4;
+ }
+
+ protected override void PopIn()
+ {
+ if (Alpha < 0.5f)
+ // reset animation if the user can't see us.
+ rotate();
+
+ MainContents.ScaleTo(1, TRANSITION_DURATION, Easing.OutQuint);
+ this.FadeIn(TRANSITION_DURATION * 2, Easing.OutQuint);
+ }
+
+ protected override void PopOut()
+ {
+ MainContents.ScaleTo(0.8f, TRANSITION_DURATION / 2, Easing.In);
+ this.FadeOut(TRANSITION_DURATION, Easing.OutQuint);
+ }
+
+ private void rotate()
+ {
+ spinner.Spin(spin_duration * 3.5f, RotationDirection.Clockwise);
+
+ MainContents.RotateTo(0).Then()
+ .RotateTo(90, spin_duration, Easing.InOutQuart).Then()
+ .RotateTo(180, spin_duration, Easing.InOutQuart).Then()
+ .RotateTo(270, spin_duration, Easing.InOutQuart).Then()
+ .RotateTo(360, spin_duration, Easing.InOutQuart).Then()
+ .Loop();
+ }
+ }
+}
diff --git a/osu.Game/Graphics/UserInterface/ProcessingOverlay.cs b/osu.Game/Graphics/UserInterface/ProcessingOverlay.cs
deleted file mode 100644
index d75e78e2d9..0000000000
--- a/osu.Game/Graphics/UserInterface/ProcessingOverlay.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Framework.Input.Events;
-using osuTK.Graphics;
-
-namespace osu.Game.Graphics.UserInterface
-{
- ///
- /// An overlay that will consume all available space and block input when required.
- /// Useful for disabling all elements in a form and showing we are waiting on a response, for instance.
- ///
- public class ProcessingOverlay : VisibilityContainer
- {
- private const float transition_duration = 200;
-
- public ProcessingOverlay()
- {
- RelativeSizeAxes = Axes.Both;
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- InternalChildren = new Drawable[]
- {
- new Box
- {
- Colour = Color4.Black,
- RelativeSizeAxes = Axes.Both,
- Alpha = 0.9f,
- },
- new LoadingAnimation { State = { Value = Visibility.Visible } }
- };
- }
-
- protected override bool Handle(UIEvent e)
- {
- return true;
- }
-
- protected override void PopIn()
- {
- this.FadeIn(transition_duration * 2, Easing.OutQuint);
- }
-
- protected override void PopOut()
- {
- this.FadeOut(transition_duration, Easing.OutQuint);
- }
- }
-}
diff --git a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs
index ea274284ac..e83d899469 100644
--- a/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs
+++ b/osu.Game/Input/Bindings/DatabasedKeyBindingContainer.cs
@@ -31,8 +31,9 @@ namespace osu.Game.Input.Bindings
/// A reference to identify the current . Used to lookup mappings. Null for global mappings.
/// An optional variant for the specified . Used when a ruleset has more than one possible keyboard layouts.
/// Specify how to deal with multiple matches of s and s.
- public DatabasedKeyBindingContainer(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None)
- : base(simultaneousMode)
+ /// Specify how to deal with exact matches.
+ public DatabasedKeyBindingContainer(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None, KeyCombinationMatchingMode matchingMode = KeyCombinationMatchingMode.Any)
+ : base(simultaneousMode, matchingMode)
{
this.ruleset = ruleset;
this.variant = variant;
diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs
index 7763577a14..71771abede 100644
--- a/osu.Game/Input/Bindings/GlobalActionContainer.cs
+++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs
@@ -15,6 +15,7 @@ namespace osu.Game.Input.Bindings
private readonly Drawable handler;
public GlobalActionContainer(OsuGameBase game)
+ : base(matchingMode: KeyCombinationMatchingMode.Modifiers)
{
if (game is IKeyBindingHandler)
handler = game;
@@ -38,6 +39,9 @@ namespace osu.Game.Input.Bindings
new KeyBinding(InputKey.Escape, GlobalAction.Back),
new KeyBinding(InputKey.ExtraMouseButton1, GlobalAction.Back),
+ new KeyBinding(InputKey.Up, GlobalAction.SelectPrevious),
+ new KeyBinding(InputKey.Down, GlobalAction.SelectNext),
+
new KeyBinding(InputKey.Space, GlobalAction.Select),
new KeyBinding(InputKey.Enter, GlobalAction.Select),
new KeyBinding(InputKey.KeypadEnter, GlobalAction.Select),
@@ -54,10 +58,11 @@ namespace osu.Game.Input.Bindings
public IEnumerable AudioControlKeyBindings => new[]
{
- new KeyBinding(InputKey.Up, GlobalAction.IncreaseVolume),
- new KeyBinding(InputKey.MouseWheelUp, GlobalAction.IncreaseVolume),
- new KeyBinding(InputKey.Down, GlobalAction.DecreaseVolume),
- new KeyBinding(InputKey.MouseWheelDown, GlobalAction.DecreaseVolume),
+ new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume),
+ new KeyBinding(new[] { InputKey.Alt, InputKey.MouseWheelUp }, GlobalAction.IncreaseVolume),
+ new KeyBinding(new[] { InputKey.Alt, InputKey.Down }, GlobalAction.DecreaseVolume),
+ new KeyBinding(new[] { InputKey.Alt, InputKey.MouseWheelDown }, GlobalAction.DecreaseVolume),
+
new KeyBinding(InputKey.F4, GlobalAction.ToggleMute),
new KeyBinding(InputKey.TrackPrevious, GlobalAction.MusicPrev),
@@ -141,5 +146,11 @@ namespace osu.Game.Input.Bindings
[Description("Toggle now playing overlay")]
ToggleNowPlaying,
+
+ [Description("Previous Selection")]
+ SelectPrevious,
+
+ [Description("Next Selection")]
+ SelectNext,
}
}
diff --git a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs
new file mode 100644
index 0000000000..22316b0380
--- /dev/null
+++ b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.Designer.cs
@@ -0,0 +1,506 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using osu.Game.Database;
+
+namespace osu.Game.Migrations
+{
+ [DbContext(typeof(OsuDbContext))]
+ [Migration("20200302094919_RefreshVolumeBindings")]
+ partial class RefreshVolumeBindings
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "2.2.6-servicing-10079");
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("ApproachRate");
+
+ b.Property("CircleSize");
+
+ b.Property("DrainRate");
+
+ b.Property("OverallDifficulty");
+
+ b.Property("SliderMultiplier");
+
+ b.Property("SliderTickRate");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapDifficulty");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("AudioLeadIn");
+
+ b.Property("BPM");
+
+ b.Property("BaseDifficultyID");
+
+ b.Property("BeatDivisor");
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("Countdown");
+
+ b.Property("DistanceSpacing");
+
+ b.Property("GridSize");
+
+ b.Property("Hash");
+
+ b.Property("Hidden");
+
+ b.Property("Length");
+
+ b.Property("LetterboxInBreaks");
+
+ b.Property("MD5Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapID");
+
+ b.Property("Path");
+
+ b.Property("RulesetID");
+
+ b.Property("SpecialStyle");
+
+ b.Property("StackLeniency");
+
+ b.Property("StarDifficulty");
+
+ b.Property("Status");
+
+ b.Property("StoredBookmarks");
+
+ b.Property("TimelineZoom");
+
+ b.Property("Version");
+
+ b.Property("WidescreenStoryboard");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BaseDifficultyID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("Hash");
+
+ b.HasIndex("MD5Hash");
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapID")
+ .IsUnique();
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("BeatmapInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Artist");
+
+ b.Property("ArtistUnicode");
+
+ b.Property("AudioFile");
+
+ b.Property("AuthorString")
+ .HasColumnName("Author");
+
+ b.Property("BackgroundFile");
+
+ b.Property("PreviewTime");
+
+ b.Property("Source");
+
+ b.Property("Tags");
+
+ b.Property("Title");
+
+ b.Property("TitleUnicode");
+
+ b.Property("VideoFile");
+
+ b.HasKey("ID");
+
+ b.ToTable("BeatmapMetadata");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("BeatmapSetInfoID");
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapSetInfoID");
+
+ b.HasIndex("FileInfoID");
+
+ b.ToTable("BeatmapSetFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("DateAdded");
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MetadataID");
+
+ b.Property("OnlineBeatmapSetID");
+
+ b.Property("Protected");
+
+ b.Property("Status");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.HasIndex("MetadataID");
+
+ b.HasIndex("OnlineBeatmapSetID")
+ .IsUnique();
+
+ b.ToTable("BeatmapSetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Key")
+ .HasColumnName("Key");
+
+ b.Property("RulesetID");
+
+ b.Property("SkinInfoID");
+
+ b.Property("StringValue")
+ .HasColumnName("Value");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("SkinInfoID");
+
+ b.HasIndex("RulesetID", "Variant");
+
+ 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")
+ .ValueGeneratedOnAdd();
+
+ b.Property("IntAction")
+ .HasColumnName("Action");
+
+ b.Property("KeysString")
+ .HasColumnName("Keys");
+
+ b.Property("RulesetID");
+
+ b.Property("Variant");
+
+ b.HasKey("ID");
+
+ b.HasIndex("IntAction");
+
+ b.HasIndex("RulesetID", "Variant");
+
+ b.ToTable("KeyBinding");
+ });
+
+ modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Available");
+
+ b.Property("InstantiationInfo");
+
+ b.Property("Name");
+
+ b.Property("ShortName");
+
+ b.HasKey("ID");
+
+ b.HasIndex("Available");
+
+ b.HasIndex("ShortName")
+ .IsUnique();
+
+ b.ToTable("RulesetInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.Property("ScoreInfoID");
+
+ b.HasKey("ID");
+
+ b.HasIndex("FileInfoID");
+
+ b.HasIndex("ScoreInfoID");
+
+ b.ToTable("ScoreFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Accuracy")
+ .HasColumnType("DECIMAL(1,4)");
+
+ b.Property("BeatmapInfoID");
+
+ b.Property("Combo");
+
+ b.Property("Date");
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("MaxCombo");
+
+ b.Property("ModsJson")
+ .HasColumnName("Mods");
+
+ b.Property("OnlineScoreID");
+
+ b.Property("PP");
+
+ b.Property("Rank");
+
+ b.Property("RulesetID");
+
+ b.Property("StatisticsJson")
+ .HasColumnName("Statistics");
+
+ b.Property("TotalScore");
+
+ b.Property("UserID")
+ .HasColumnName("UserID");
+
+ b.Property("UserString")
+ .HasColumnName("User");
+
+ b.HasKey("ID");
+
+ b.HasIndex("BeatmapInfoID");
+
+ b.HasIndex("OnlineScoreID")
+ .IsUnique();
+
+ b.HasIndex("RulesetID");
+
+ b.ToTable("ScoreInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("FileInfoID");
+
+ b.Property("Filename")
+ .IsRequired();
+
+ b.Property("SkinInfoID");
+
+ b.HasKey("ID");
+
+ b.HasIndex("FileInfoID");
+
+ b.HasIndex("SkinInfoID");
+
+ b.ToTable("SkinFileInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b =>
+ {
+ b.Property("ID")
+ .ValueGeneratedOnAdd();
+
+ b.Property("Creator");
+
+ b.Property("DeletePending");
+
+ b.Property("Hash");
+
+ b.Property("Name");
+
+ b.HasKey("ID");
+
+ b.HasIndex("DeletePending");
+
+ b.HasIndex("Hash")
+ .IsUnique();
+
+ b.ToTable("SkinInfo");
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty")
+ .WithMany()
+ .HasForeignKey("BaseDifficultyID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet")
+ .WithMany("Beatmaps")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("Beatmaps")
+ .HasForeignKey("MetadataID");
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo")
+ .WithMany("Files")
+ .HasForeignKey("BeatmapSetInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata")
+ .WithMany("BeatmapSets")
+ .HasForeignKey("MetadataID");
+ });
+
+ modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b =>
+ {
+ b.HasOne("osu.Game.Skinning.SkinInfo")
+ .WithMany("Settings")
+ .HasForeignKey("SkinInfoID");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b =>
+ {
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Scoring.ScoreInfo")
+ .WithMany("Files")
+ .HasForeignKey("ScoreInfoID");
+ });
+
+ modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b =>
+ {
+ b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap")
+ .WithMany("Scores")
+ .HasForeignKey("BeatmapInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset")
+ .WithMany()
+ .HasForeignKey("RulesetID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+
+ modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b =>
+ {
+ b.HasOne("osu.Game.IO.FileInfo", "FileInfo")
+ .WithMany()
+ .HasForeignKey("FileInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+
+ b.HasOne("osu.Game.Skinning.SkinInfo")
+ .WithMany("Files")
+ .HasForeignKey("SkinInfoID")
+ .OnDelete(DeleteBehavior.Cascade);
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs
new file mode 100644
index 0000000000..ec4475971c
--- /dev/null
+++ b/osu.Game/Migrations/20200302094919_RefreshVolumeBindings.cs
@@ -0,0 +1,16 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace osu.Game.Migrations
+{
+ public partial class RefreshVolumeBindings : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.Sql("DELETE FROM KeyBinding WHERE action in (6,7)");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ }
+ }
+}
diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
index a6d9d1f3cb..bc4fc3342d 100644
--- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
+++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs
@@ -43,7 +43,7 @@ namespace osu.Game.Migrations
b.Property("ID")
.ValueGeneratedOnAdd();
- b.Property("AudioLeadIn");
+ b.Property("AudioLeadIn");
b.Property("BPM");
diff --git a/osu.Game/Online/API/Requests/GetCommentsRequest.cs b/osu.Game/Online/API/Requests/GetCommentsRequest.cs
index 7763501860..24dae4adf1 100644
--- a/osu.Game/Online/API/Requests/GetCommentsRequest.cs
+++ b/osu.Game/Online/API/Requests/GetCommentsRequest.cs
@@ -10,27 +10,32 @@ namespace osu.Game.Online.API.Requests
{
public class GetCommentsRequest : APIRequest
{
- private readonly long id;
- private readonly int page;
+ private readonly long commentableId;
private readonly CommentableType type;
private readonly CommentsSortCriteria sort;
+ private readonly int page;
+ private readonly long? parentId;
- public GetCommentsRequest(CommentableType type, long id, CommentsSortCriteria sort = CommentsSortCriteria.New, int page = 1)
+ public GetCommentsRequest(long commentableId, CommentableType type, CommentsSortCriteria sort = CommentsSortCriteria.New, int page = 1, long? parentId = null)
{
+ this.commentableId = commentableId;
this.type = type;
this.sort = sort;
- this.id = id;
this.page = page;
+ this.parentId = parentId;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
+ req.AddParameter("commentable_id", commentableId.ToString());
req.AddParameter("commentable_type", type.ToString().Underscore().ToLowerInvariant());
- req.AddParameter("commentable_id", id.ToString());
- req.AddParameter("sort", sort.ToString().ToLowerInvariant());
req.AddParameter("page", page.ToString());
+ req.AddParameter("sort", sort.ToString().ToLowerInvariant());
+
+ if (parentId != null)
+ req.AddParameter("parent_id", parentId.ToString());
return req;
}
diff --git a/osu.Game/Online/API/Requests/GetRoomRequest.cs b/osu.Game/Online/API/Requests/GetRoomRequest.cs
new file mode 100644
index 0000000000..531e1857de
--- /dev/null
+++ b/osu.Game/Online/API/Requests/GetRoomRequest.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Online.Multiplayer;
+
+namespace osu.Game.Online.API.Requests
+{
+ public class GetRoomRequest : APIRequest
+ {
+ private readonly int roomId;
+
+ public GetRoomRequest(int roomId)
+ {
+ this.roomId = roomId;
+ }
+
+ protected override string Target => $"rooms/{roomId}";
+ }
+}
diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs
index 3e38c3067b..05a24cec0e 100644
--- a/osu.Game/Online/API/Requests/Responses/Comment.cs
+++ b/osu.Game/Online/API/Requests/Responses/Comment.cs
@@ -4,8 +4,6 @@
using Newtonsoft.Json;
using osu.Game.Users;
using System;
-using System.Collections.Generic;
-using System.Linq;
namespace osu.Game.Online.API.Requests.Responses
{
@@ -17,8 +15,6 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"parent_id")]
public long? ParentId { get; set; }
- public readonly List ChildComments = new List();
-
public Comment ParentComment { get; set; }
[JsonProperty(@"user_id")]
@@ -71,7 +67,5 @@ namespace osu.Game.Online.API.Requests.Responses
public bool HasMessage => !string.IsNullOrEmpty(Message);
public bool IsVoted { get; set; }
-
- public int DeletedChildrenCount => ChildComments.Count(c => c.IsDeleted);
}
}
diff --git a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs
index 9b3ef8b6e5..d76ede67cd 100644
--- a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs
+++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs
@@ -9,31 +9,8 @@ namespace osu.Game.Online.API.Requests.Responses
{
public class CommentBundle
{
- private List comments;
-
[JsonProperty(@"comments")]
- public List Comments
- {
- get => comments;
- set
- {
- comments = value;
- comments.ForEach(child =>
- {
- if (child.ParentId != null)
- {
- comments.ForEach(parent =>
- {
- if (parent.Id == child.ParentId)
- {
- parent.ChildComments.Add(child);
- child.ParentComment = parent;
- }
- });
- }
- });
- }
- }
+ public List Comments { get; set; }
[JsonProperty(@"has_more")]
public bool HasMore { get; set; }
@@ -58,6 +35,7 @@ namespace osu.Game.Online.API.Requests.Responses
userVotes = value;
Comments.ForEach(c => c.IsVoted = value.Contains(c.Id));
+ IncludedComments.ForEach(c => c.IsVoted = value.Contains(c.Id));
}
}
@@ -81,6 +59,15 @@ namespace osu.Game.Online.API.Requests.Responses
if (c.EditedById == u.Id)
c.EditedUser = u;
});
+
+ IncludedComments.ForEach(c =>
+ {
+ if (c.UserId == u.Id)
+ c.User = u;
+
+ if (c.EditedById == u.Id)
+ c.EditedUser = u;
+ });
});
}
}
diff --git a/osu.Game/Online/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs
index 50cb58c6ab..20bda4601f 100644
--- a/osu.Game/Online/Leaderboards/DrawableRank.cs
+++ b/osu.Game/Online/Leaderboards/DrawableRank.cs
@@ -58,7 +58,7 @@ namespace osu.Game.Online.Leaderboards
Spacing = new Vector2(-3, 0),
Padding = new MarginPadding { Top = 5 },
Colour = getRankNameColour(),
- Font = OsuFont.GetFont(Typeface.Venera, 25),
+ Font = OsuFont.Numeric.With(size: 25),
Text = getRankName(),
ShadowColour = Color4.Black.Opacity(0.3f),
ShadowOffset = new Vector2(0, 0.08f),
diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs
index 71859d3aeb..e2a817aaff 100644
--- a/osu.Game/Online/Leaderboards/Leaderboard.cs
+++ b/osu.Game/Online/Leaderboards/Leaderboard.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Online.Leaderboards
private FillFlowContainer scrollFlow;
- private readonly LoadingAnimation loading;
+ private readonly LoadingSpinner loading;
private ScheduledDelegate showScoresDelegate;
private CancellationTokenSource showScoresCancellationSource;
@@ -202,7 +202,7 @@ namespace osu.Game.Online.Leaderboards
}
},
},
- loading = new LoadingAnimation(),
+ loading = new LoadingSpinner(),
placeholderContainer = new Container
{
RelativeSizeAxes = Axes.Both
diff --git a/osu.Game/Online/Multiplayer/PlaylistItem.cs b/osu.Game/Online/Multiplayer/PlaylistItem.cs
index 11e4854174..9d6e8eb8e3 100644
--- a/osu.Game/Online/Multiplayer/PlaylistItem.cs
+++ b/osu.Game/Online/Multiplayer/PlaylistItem.cs
@@ -65,9 +65,7 @@ namespace osu.Game.Online.Multiplayer
public void MapObjects(BeatmapManager beatmaps, RulesetStore rulesets)
{
- // If we don't have an api beatmap, the request occurred as a result of room creation, so we can query the local beatmap instead
- // Todo: Is this a bug? Room creation only returns the beatmap ID
- Beatmap.Value = apiBeatmap == null ? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == BeatmapID) : apiBeatmap.ToBeatmap(rulesets);
+ Beatmap.Value = apiBeatmap.ToBeatmap(rulesets);
Ruleset.Value = rulesets.GetRuleset(RulesetID);
Ruleset rulesetInstance = Ruleset.Value.CreateInstance();
diff --git a/osu.Game/Online/Multiplayer/Room.cs b/osu.Game/Online/Multiplayer/Room.cs
index 2bfcc019fa..d074ac9775 100644
--- a/osu.Game/Online/Multiplayer/Room.cs
+++ b/osu.Game/Online/Multiplayer/Room.cs
@@ -59,8 +59,8 @@ namespace osu.Game.Online.Multiplayer
public Bindable MaxParticipants { get; private set; } = new Bindable();
[Cached]
- [JsonIgnore]
- public BindableList Participants { get; private set; } = new BindableList();
+ [JsonProperty("recent_participants")]
+ public BindableList RecentParticipants { get; private set; } = new BindableList();
[Cached]
public Bindable ParticipantCount { get; private set; } = new Bindable();
@@ -118,25 +118,16 @@ namespace osu.Game.Online.Multiplayer
if (DateTimeOffset.Now >= EndDate.Value)
Status.Value = new RoomStatusEnded();
- // transfer local beatmaps across to ensure we have Metadata available (CreateRoomRequest does not give us metadata as expected)
- foreach (var item in other.Playlist)
- {
- var localItem = Playlist.FirstOrDefault(i => i.BeatmapID == item.BeatmapID);
-
- if (localItem != null)
- item.Beatmap.Value.Metadata = localItem.Beatmap.Value.Metadata;
- }
-
if (!Playlist.SequenceEqual(other.Playlist))
{
Playlist.Clear();
Playlist.AddRange(other.Playlist);
}
- if (!Participants.SequenceEqual(other.Participants))
+ if (!RecentParticipants.SequenceEqual(other.RecentParticipants))
{
- Participants.Clear();
- Participants.AddRange(other.Participants);
+ RecentParticipants.Clear();
+ RecentParticipants.AddRange(other.RecentParticipants);
}
Position = other.Position;
diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs
index 689c1c0afb..b52e3d9e3c 100644
--- a/osu.Game/Online/OnlineViewContainer.cs
+++ b/osu.Game/Online/OnlineViewContainer.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Online
///
public abstract class OnlineViewContainer : Container, IOnlineComponent
{
- protected LoadingAnimation LoadingAnimation { get; private set; }
+ protected LoadingSpinner LoadingSpinner { get; private set; }
protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both };
@@ -41,7 +41,7 @@ namespace osu.Game.Online
{
Content,
placeholder = new LoginPlaceholder(placeholderMessage),
- LoadingAnimation = new LoadingAnimation
+ LoadingSpinner = new LoadingSpinner
{
Alpha = 0,
}
@@ -63,19 +63,19 @@ namespace osu.Game.Online
PopContentOut(Content);
placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_duration, Easing.OutQuint);
placeholder.FadeInFromZero(2 * transform_duration, Easing.OutQuint);
- LoadingAnimation.Hide();
+ LoadingSpinner.Hide();
break;
case APIState.Online:
PopContentIn(Content);
placeholder.FadeOut(transform_duration / 2, Easing.OutQuint);
- LoadingAnimation.Hide();
+ LoadingSpinner.Hide();
break;
case APIState.Failing:
case APIState.Connecting:
PopContentOut(Content);
- LoadingAnimation.Show();
+ LoadingSpinner.Show();
placeholder.FadeOut(transform_duration / 2, Easing.OutQuint);
break;
}
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 100730d40d..1b2fd658f4 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -25,6 +25,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
+using osu.Framework.Input.Events;
using osu.Framework.Platform;
using osu.Framework.Threading;
using osu.Game.Beatmaps;
@@ -42,6 +43,7 @@ using osu.Game.Overlays.Volume;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens.Select;
+using osu.Game.Updater;
using osu.Game.Utils;
using LogLevel = osu.Framework.Logging.LogLevel;
@@ -389,24 +391,35 @@ namespace osu.Game
protected virtual Loader CreateLoader() => new Loader();
+ protected virtual UpdateManager CreateUpdateManager() => new UpdateManager();
+
protected override Container CreateScalingContainer() => new ScalingContainer(ScalingMode.Everything);
#region Beatmap progression
private void beatmapChanged(ValueChangedEvent beatmap)
{
- var nextBeatmap = beatmap.NewValue;
- if (nextBeatmap?.Track != null)
- nextBeatmap.Track.Completed += currentTrackCompleted;
-
- var oldBeatmap = beatmap.OldValue;
- if (oldBeatmap?.Track != null)
- oldBeatmap.Track.Completed -= currentTrackCompleted;
+ beatmap.OldValue?.CancelAsyncLoad();
updateModDefaults();
- oldBeatmap?.CancelAsyncLoad();
- nextBeatmap?.BeginAsyncLoad();
+ var newBeatmap = beatmap.NewValue;
+
+ if (newBeatmap != null)
+ {
+ newBeatmap.Track.Completed += () => Scheduler.AddOnce(() => trackCompleted(newBeatmap));
+ newBeatmap.BeginAsyncLoad();
+ }
+
+ void trackCompleted(WorkingBeatmap b)
+ {
+ // the source of track completion is the audio thread, so the beatmap may have changed before firing.
+ if (Beatmap.Value != b)
+ return;
+
+ if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled)
+ MusicController.NextTrack();
+ }
}
private void modsChanged(ValueChangedEvent> mods)
@@ -427,12 +440,6 @@ namespace osu.Game
}
}
- private void currentTrackCompleted() => Schedule(() =>
- {
- if (!Beatmap.Value.Track.Looping && !Beatmap.Disabled)
- musicController.NextTrack();
- });
-
#endregion
private ScheduledDelegate performFromMainMenuTask;
@@ -584,7 +591,7 @@ namespace osu.Game
loadComponentSingleFile(new OnScreenDisplay(), Add, true);
- loadComponentSingleFile(musicController = new MusicController(), Add, true);
+ loadComponentSingleFile(MusicController = new MusicController(), Add, true);
loadComponentSingleFile(notifications = new NotificationOverlay
{
@@ -598,6 +605,7 @@ namespace osu.Game
//overlay elements
loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true);
loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true);
+ var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true);
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true);
@@ -626,6 +634,7 @@ namespace osu.Game
chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible;
Add(externalLinkOpener = new ExternalLinkOpener());
+ Add(CreateUpdateManager()); // dependency on notification overlay
// side overlays which cancel each other.
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
@@ -654,7 +663,7 @@ namespace osu.Game
}
// ensure only one of these overlays are open at once.
- var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay };
+ var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay, rankingsOverlay };
foreach (var overlay in singleDisplayOverlays)
{
@@ -804,6 +813,13 @@ namespace osu.Game
return d;
}
+ protected override bool OnScroll(ScrollEvent e)
+ {
+ // forward any unhandled mouse scroll events to the volume control.
+ volume.Adjust(GlobalAction.IncreaseVolume, e.ScrollDelta.Y, e.IsPrecise);
+ return true;
+ }
+
public bool OnPressed(GlobalAction action)
{
if (introScreen == null) return false;
@@ -884,7 +900,7 @@ namespace osu.Game
private ScalingContainer screenContainer;
- private MusicController musicController;
+ protected MusicController MusicController { get; private set; }
protected override bool OnExiting()
{
@@ -942,7 +958,7 @@ namespace osu.Game
{
OverlayActivationMode.Value = newOsuScreen.InitialOverlayActivationMode;
- musicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;
+ MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;
if (newOsuScreen.HideOverlaysOnEnter)
CloseAllOverlays();
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index 07c9d37a86..b2277e2abf 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -97,7 +97,7 @@ namespace osu.Game
public bool IsDeployedBuild => AssemblyVersion.Major > 0;
- public string Version
+ public virtual string Version
{
get
{
@@ -157,9 +157,14 @@ namespace osu.Game
AddFont(Resources, @"Fonts/Exo2.0-Black");
AddFont(Resources, @"Fonts/Exo2.0-BlackItalic");
- AddFont(Resources, @"Fonts/Venera");
+ AddFont(Resources, @"Fonts/Torus-SemiBold");
+ AddFont(Resources, @"Fonts/Torus-Bold");
+ AddFont(Resources, @"Fonts/Torus-Regular");
+ AddFont(Resources, @"Fonts/Torus-Light");
+
AddFont(Resources, @"Fonts/Venera-Light");
- AddFont(Resources, @"Fonts/Venera-Medium");
+ AddFont(Resources, @"Fonts/Venera-Bold");
+ AddFont(Resources, @"Fonts/Venera-Black");
runMigrations();
@@ -206,6 +211,10 @@ namespace osu.Game
Audio.Tracks.AddAdjustment(AdjustableProperty.Volume, new BindableDouble(0.8));
Beatmap = new NonNullableBindable(defaultBeatmap);
+
+ // ScheduleAfterChildren is safety against something in the current frame accessing the previous beatmap's track
+ // and potentially causing a reload of it after just unloading.
+ // Note that the reason for this being added *has* been resolved, so it may be feasible to removed this if required.
Beatmap.BindValueChanged(b => ScheduleAfterChildren(() =>
{
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
diff --git a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
index be3a84ca00..2576900db8 100644
--- a/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
+++ b/osu.Game/Overlays/AccountCreation/ScreenEntry.cs
@@ -40,7 +40,7 @@ namespace osu.Game.Overlays.AccountCreation
private IEnumerable characterCheckText;
private OsuTextBox[] textboxes;
- private ProcessingOverlay processingOverlay;
+ private LoadingLayer loadingLayer;
[Resolved]
private GameHost host { get; set; }
@@ -48,9 +48,11 @@ namespace osu.Game.Overlays.AccountCreation
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
+ FillFlowContainer mainContent;
+
InternalChildren = new Drawable[]
{
- new FillFlowContainer
+ mainContent = new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
@@ -122,7 +124,7 @@ namespace osu.Game.Overlays.AccountCreation
},
},
},
- processingOverlay = new ProcessingOverlay { Alpha = 0 }
+ loadingLayer = new LoadingLayer(mainContent)
};
textboxes = new[] { usernameTextBox, emailTextBox, passwordTextBox };
@@ -142,7 +144,7 @@ namespace osu.Game.Overlays.AccountCreation
public override void OnEntering(IScreen last)
{
base.OnEntering(last);
- processingOverlay.Hide();
+ loadingLayer.Hide();
if (host?.OnScreenKeyboardOverlapsGameWindow != true)
focusNextTextbox();
@@ -160,7 +162,7 @@ namespace osu.Game.Overlays.AccountCreation
emailAddressDescription.ClearErrors();
passwordDescription.ClearErrors();
- processingOverlay.Show();
+ loadingLayer.Show();
Task.Run(() =>
{
@@ -193,7 +195,7 @@ namespace osu.Game.Overlays.AccountCreation
}
registerShake.Shake();
- processingOverlay.Hide();
+ loadingLayer.Hide();
return;
}
diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs
index 2449f561c1..ebe4b7fe61 100644
--- a/osu.Game/Overlays/BeatmapListingOverlay.cs
+++ b/osu.Game/Overlays/BeatmapListingOverlay.cs
@@ -15,6 +15,7 @@ using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapListing;
using osu.Game.Overlays.Direct;
@@ -34,7 +35,6 @@ namespace osu.Game.Overlays
private SearchBeatmapSetsRequest getSetsRequest;
- private Container panelsPlaceholder;
private Drawable currentContent;
private BeatmapListingSearchSection searchSection;
private BeatmapListingSortTabControl sortControl;
@@ -121,12 +121,21 @@ namespace osu.Game.Overlays
}
}
},
- panelsPlaceholder = new Container
+ new Container
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding { Horizontal = 20 },
- }
+ Children = new Drawable[]
+ {
+ panelTarget = new Container
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ },
+ loadingLayer = new LoadingLayer(panelTarget),
+ }
+ },
}
}
}
@@ -183,6 +192,9 @@ namespace osu.Game.Overlays
private ScheduledDelegate queryChangedDebounce;
+ private LoadingLayer loadingLayer;
+ private Container panelTarget;
+
private void queueUpdateSearch(bool queryTextChanged = false)
{
getSetsRequest?.Cancel();
@@ -204,7 +216,7 @@ namespace osu.Game.Overlays
previewTrackManager.StopAnyPlaying(this);
- currentContent?.FadeColour(Color4.DimGray, 400, Easing.OutQuint);
+ loadingLayer.Show();
getSetsRequest = new SearchBeatmapSetsRequest(searchSection.SearchParameters.Value.Query, searchSection.SearchParameters.Value.Ruleset)
{
@@ -254,6 +266,8 @@ namespace osu.Game.Overlays
private void addContentToPlaceholder(Drawable content)
{
+ loadingLayer.Hide();
+
Drawable lastContent = currentContent;
if (lastContent != null)
@@ -267,7 +281,7 @@ namespace osu.Game.Overlays
lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y);
}
- panelsPlaceholder.Add(currentContent = content);
+ panelTarget.Add(currentContent = content);
currentContent.FadeIn(200, Easing.OutQuint);
}
diff --git a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs
index 096e91b65b..31c1439c8f 100644
--- a/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs
+++ b/osu.Game/Overlays/BeatmapSet/AuthorInfo.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -50,7 +51,7 @@ namespace osu.Game.Overlays.BeatmapSet
fields.Children = new Drawable[]
{
new Field("mapped by", BeatmapSet.Metadata.Author.Username, OsuFont.GetFont(weight: FontWeight.Regular, italics: true)),
- new Field("submitted on", online.Submitted.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold))
+ new Field("submitted", online.Submitted, OsuFont.GetFont(weight: FontWeight.Bold))
{
Margin = new MarginPadding { Top = 5 },
},
@@ -58,11 +59,11 @@ namespace osu.Game.Overlays.BeatmapSet
if (online.Ranked.HasValue)
{
- fields.Add(new Field("ranked on", online.Ranked.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)));
+ fields.Add(new Field(online.Status.ToString().ToLowerInvariant(), online.Ranked.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
}
else if (online.LastUpdated.HasValue)
{
- fields.Add(new Field("last updated on", online.LastUpdated.Value.ToString(@"MMMM d, yyyy"), OsuFont.GetFont(weight: FontWeight.Bold)));
+ fields.Add(new Field("last updated", online.LastUpdated.Value, OsuFont.GetFont(weight: FontWeight.Bold)));
}
}
@@ -76,7 +77,7 @@ namespace osu.Game.Overlays.BeatmapSet
new Container
{
AutoSizeAxes = Axes.Both,
- CornerRadius = 3,
+ CornerRadius = 4,
Masking = true,
Child = avatar = new UpdateableAvatar
{
@@ -87,7 +88,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
Colour = Color4.Black.Opacity(0.25f),
Type = EdgeEffectType.Shadow,
- Radius = 3,
+ Radius = 4,
Offset = new Vector2(0f, 1f),
},
},
@@ -117,15 +118,34 @@ namespace osu.Game.Overlays.BeatmapSet
new OsuSpriteText
{
Text = $"{first} ",
- Font = OsuFont.GetFont(size: 13)
+ Font = OsuFont.GetFont(size: 11)
},
new OsuSpriteText
{
Text = second,
- Font = secondFont.With(size: 13)
+ Font = secondFont.With(size: 11)
},
};
}
+
+ public Field(string first, DateTimeOffset second, FontUsage secondFont)
+ {
+ AutoSizeAxes = Axes.Both;
+ Direction = FillDirection.Horizontal;
+
+ Children = new[]
+ {
+ new OsuSpriteText
+ {
+ Text = $"{first} ",
+ Font = OsuFont.GetFont(size: 13)
+ },
+ new DrawableDate(second)
+ {
+ Font = secondFont.With(size: 13)
+ }
+ };
+ }
}
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
index 7092b860a0..ba0a62ec2f 100644
--- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs
+++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
@@ -105,7 +105,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
TooltipText = name;
RelativeSizeAxes = Axes.X;
- AutoSizeAxes = Axes.Y;
+ Height = 24f;
Children = new Drawable[]
{
@@ -113,7 +113,8 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- AutoSizeAxes = Axes.Both,
+ AutoSizeAxes = Axes.X,
+ RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
new SpriteIcon
@@ -121,7 +122,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Icon = FontAwesome.Solid.Square,
- Size = new Vector2(13),
+ Size = new Vector2(12),
Rotation = 45,
Colour = OsuColour.FromHex(@"441288"),
},
@@ -130,7 +131,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
Icon = icon,
- Size = new Vector2(13),
+ Size = new Vector2(12),
Colour = OsuColour.FromHex(@"f7dd55"),
Scale = new Vector2(0.8f),
},
@@ -139,7 +140,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 10 },
- Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold),
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
},
},
},
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
index bf2a92cd4f..66886b0882 100644
--- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs
@@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
-using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -19,7 +18,6 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet
{
@@ -34,7 +32,6 @@ namespace osu.Game.Overlays.BeatmapSet
public readonly DifficultiesContainer Difficulties;
public readonly Bindable Beatmap = new Bindable();
-
private BeatmapSetInfo beatmapSet;
public BeatmapSetInfo BeatmapSet
@@ -67,7 +64,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2) },
+ Margin = new MarginPadding { Left = -(tile_icon_padding + tile_spacing / 2), Bottom = 10 },
OnLostHover = () =>
{
showBeatmap(Beatmap.Value);
@@ -77,7 +74,6 @@ namespace osu.Game.Overlays.BeatmapSet
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
- Margin = new MarginPadding { Top = 10 },
Spacing = new Vector2(5f),
Children = new[]
{
@@ -85,13 +81,13 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
- Font = OsuFont.GetFont(size: 20, weight: FontWeight.Bold)
+ Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold)
},
starRating = new OsuSpriteText
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
- Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold),
+ Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold),
Text = "Star Difficulty",
Alpha = 0,
Margin = new MarginPadding { Bottom = 1 },
@@ -192,9 +188,11 @@ namespace osu.Game.Overlays.BeatmapSet
public class DifficultySelectorButton : OsuClickableContainer, IStateful
{
private const float transition_duration = 100;
- private const float size = 52;
+ private const float size = 54;
+ private const float background_size = size - 2;
- private readonly Container bg;
+ private readonly Container background;
+ private readonly Box backgroundBox;
private readonly DifficultyIcon icon;
public readonly BeatmapInfo Beatmap;
@@ -230,16 +228,16 @@ namespace osu.Game.Overlays.BeatmapSet
Children = new Drawable[]
{
- bg = new Container
+ background = new Container
{
- RelativeSizeAxes = Axes.Both,
+ Size = new Vector2(background_size),
Masking = true,
CornerRadius = 4,
- Child = new Box
+ Child = backgroundBox = new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black.Opacity(0.5f),
- },
+ Alpha = 0.5f
+ }
},
icon = new DifficultyIcon(beatmap, shouldShowTooltip: false)
{
@@ -273,15 +271,21 @@ namespace osu.Game.Overlays.BeatmapSet
private void fadeIn()
{
- bg.FadeIn(transition_duration);
+ background.FadeIn(transition_duration);
icon.FadeIn(transition_duration);
}
private void fadeOut()
{
- bg.FadeOut();
+ background.FadeOut();
icon.FadeTo(0.7f, transition_duration);
}
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ backgroundBox.Colour = colourProvider.Background6;
+ }
}
private class Statistic : FillFlowContainer
@@ -314,13 +318,13 @@ namespace osu.Game.Overlays.BeatmapSet
Origin = Anchor.CentreLeft,
Icon = icon,
Shadow = true,
- Size = new Vector2(13),
+ Size = new Vector2(12),
},
text = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
- Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold, italics: true)
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold, italics: true),
},
};
}
diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
new file mode 100644
index 0000000000..e6d433f7bc
--- /dev/null
+++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetLayoutSection.cs
@@ -0,0 +1,29 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Overlays.BeatmapSet
+{
+ public class BeatmapSetLayoutSection : Container
+ {
+ public BeatmapSetLayoutSection()
+ {
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ Masking = true;
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Color4.Black.Opacity(0.25f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Offset = new Vector2(0f, 1f),
+ };
+ }
+ }
+}
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
index af0987d183..742b1055b2 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
@@ -5,7 +5,6 @@ using System.Diagnostics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
@@ -25,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
private readonly BindableBool favourited = new BindableBool();
private PostBeatmapFavouriteRequest request;
- private DimmedLoadingLayer loading;
+ private LoadingLayer loading;
private readonly Bindable localUser = new Bindable();
@@ -54,14 +53,11 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
Size = new Vector2(18),
Shadow = false,
},
- loading = new DimmedLoadingLayer(0.8f, 0.5f),
+ loading = new LoadingLayer(icon, false),
});
Action = () =>
{
- if (loading.State.Value == Visibility.Visible)
- return;
-
// guaranteed by disabled state above.
Debug.Assert(BeatmapSet.Value.OnlineBeatmapSetID != null);
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
index 53003b0488..e64256b850 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs
@@ -22,6 +22,8 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public class HeaderDownloadButton : BeatmapDownloadTrackingComposite, IHasTooltip
{
+ private const int text_size = 12;
+
private readonly bool noVideo;
public string TooltipText => button.Enabled.Value ? "download this beatmap" : "login to download";
@@ -80,8 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Icon = FontAwesome.Solid.Download,
- Size = new Vector2(16),
- Margin = new MarginPadding { Right = 5 },
+ Size = new Vector2(18),
},
}
},
@@ -120,7 +121,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
new OsuSpriteText
{
Text = "Downloading...",
- Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
+ Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
};
break;
@@ -131,7 +132,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
new OsuSpriteText
{
Text = "Importing...",
- Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
+ Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
};
break;
@@ -146,12 +147,12 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
new OsuSpriteText
{
Text = "Download",
- Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold)
+ Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold)
},
new OsuSpriteText
{
Text = getVideoSuffixText(),
- Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold)
+ Font = OsuFont.GetFont(size: text_size - 2, weight: FontWeight.Bold)
},
};
this.FadeIn(200);
diff --git a/osu.Game/Overlays/BeatmapSet/Details.cs b/osu.Game/Overlays/BeatmapSet/Details.cs
index 488e181fa2..680487ffbb 100644
--- a/osu.Game/Overlays/BeatmapSet/Details.cs
+++ b/osu.Game/Overlays/BeatmapSet/Details.cs
@@ -74,7 +74,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Margin = new MarginPadding { Vertical = 10 },
+ Padding = new MarginPadding { Vertical = 10 }
},
},
new DetailBox
diff --git a/osu.Game/Overlays/BeatmapSet/Header.cs b/osu.Game/Overlays/BeatmapSet/Header.cs
index 29f09a1ad8..29c259b7f8 100644
--- a/osu.Game/Overlays/BeatmapSet/Header.cs
+++ b/osu.Game/Overlays/BeatmapSet/Header.cs
@@ -1,4 +1,4 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
@@ -45,7 +45,7 @@ namespace osu.Game.Overlays.BeatmapSet
private readonly FavouriteButton favouriteButton;
private readonly FillFlowContainer fadeContent;
- private readonly LoadingAnimation loading;
+ private readonly LoadingSpinner loading;
private readonly BeatmapSetHeader beatmapSetHeader;
[Cached(typeof(IBindable))]
@@ -144,12 +144,15 @@ namespace osu.Game.Overlays.BeatmapSet
},
}
},
- artist = new OsuSpriteText { Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true) },
+ artist = new OsuSpriteText
+ {
+ Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true),
+ Margin = new MarginPadding { Bottom = 20 }
+ },
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Margin = new MarginPadding { Top = 20 },
Child = author = new AuthorInfo(),
},
beatmapAvailability = new BeatmapAvailability(),
@@ -176,7 +179,7 @@ namespace osu.Game.Overlays.BeatmapSet
},
}
},
- loading = new LoadingAnimation
+ loading = new LoadingSpinner
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs
index 85e871baca..bac658b76e 100644
--- a/osu.Game/Overlays/BeatmapSet/Info.cs
+++ b/osu.Game/Overlays/BeatmapSet/Info.cs
@@ -3,25 +3,23 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
-using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Overlays.BeatmapSet
{
public class Info : Container
{
private const float transition_duration = 250;
- private const float metadata_width = 225;
+ private const float metadata_width = 175;
private const float spacing = 20;
+ private const float base_height = 220;
private readonly Box successRateBackground;
private readonly Box background;
@@ -41,15 +39,7 @@ namespace osu.Game.Overlays.BeatmapSet
OsuSpriteText unrankedPlaceholder;
RelativeSizeAxes = Axes.X;
- Height = 220;
- Masking = true;
- EdgeEffect = new EdgeEffectParameters
- {
- Colour = Color4.Black.Opacity(0.25f),
- Type = EdgeEffectType.Shadow,
- Radius = 3,
- Offset = new Vector2(0f, 1f),
- };
+ Height = base_height;
Children = new Drawable[]
{
@@ -135,6 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet
var setHasLeaderboard = b.NewValue?.OnlineInfo?.Status > 0;
successRate.Alpha = setHasLeaderboard ? 1 : 0;
unrankedPlaceholder.Alpha = setHasLeaderboard ? 0 : 1;
+ Height = setHasLeaderboard ? 270 : base_height;
};
}
@@ -176,8 +167,8 @@ namespace osu.Game.Overlays.BeatmapSet
new OsuSpriteText
{
Text = title,
- Font = OsuFont.GetFont(size: 14, weight: FontWeight.Black),
- Margin = new MarginPadding { Top = 20 },
+ Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
+ Margin = new MarginPadding { Top = 15 },
},
textFlow = new OsuTextFlowContainer
{
diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs
index 20a3b09db4..607355b7bf 100644
--- a/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs
+++ b/osu.Game/Overlays/BeatmapSet/LeaderboardScopeSelector.cs
@@ -3,7 +3,6 @@
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Graphics.UserInterface;
-using osu.Game.Graphics;
using osu.Framework.Allocation;
using osuTK.Graphics;
using osu.Framework.Graphics.UserInterface;
@@ -37,7 +36,6 @@ namespace osu.Game.Overlays.BeatmapSet
public ScopeSelectorTabItem(BeatmapLeaderboardScope value)
: base(value)
{
- Text.Font = OsuFont.GetFont(size: 16);
}
protected override bool OnHover(HoverEvent e)
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs
index cad37dd082..0ae8a8bef5 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/DrawableTopScore.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
AutoSizeAxes = Axes.Y;
Masking = true;
- CornerRadius = 5;
+ CornerRadius = 4;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
@@ -46,7 +46,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Vertical = 10,
Left = 10,
- Right = 25,
+ Right = 30,
},
Children = new Drawable[]
{
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs
index ba08a78a61..b2c87a1477 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/NotSupporterPlaceholder.cs
@@ -21,7 +21,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
- Spacing = new Vector2(0, 10),
+ Spacing = new Vector2(0, 20),
Children = new Drawable[]
{
new OsuSpriteText
@@ -29,9 +29,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = @"You need to be an osu!supporter to access the friend and country rankings!",
- Font = OsuFont.GetFont(weight: FontWeight.Bold),
+ Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold),
},
- text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 12))
+ text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 11))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
index 954eada612..f1250679c1 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public class ScoreTable : TableContainer
{
private const float horizontal_inset = 20;
- private const float row_height = 25;
+ private const float row_height = 22;
private const int text_size = 12;
private readonly FillFlowContainer backgroundFlow;
@@ -63,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
return;
for (int i = 0; i < value.Count; i++)
- backgroundFlow.Add(new ScoreTableRowBackground(i, value[i]));
+ backgroundFlow.Add(new ScoreTableRowBackground(i, value[i], row_height));
Columns = createHeaders(value[0]);
Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
@@ -77,17 +77,20 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
new TableColumn("rank", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)),
new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)), // grade
new TableColumn("score", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
- new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 60, maxSize: 70)),
- new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 150)),
- new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 110))
+ new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)),
+ new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 25)), // flag
+ new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 125)),
+ new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120))
};
- foreach (var statistic in score.SortedStatistics)
- columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 50, maxSize: 70)));
+ foreach (var statistic in score.SortedStatistics.Take(score.SortedStatistics.Count() - 1))
+ columns.Add(new TableColumn(statistic.Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 35, maxSize: 60)));
+
+ columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
columns.AddRange(new[]
{
- new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 40, maxSize: 70)),
+ new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)),
new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
});
@@ -96,6 +99,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private Drawable[] createContent(int index, ScoreInfo score)
{
+ var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: text_size)) { AutoSizeAxes = Axes.Both };
+ username.AddUserLink(score.User);
+
var content = new List
{
new OsuSpriteText
@@ -105,7 +111,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
},
new UpdateableRank(score.Rank)
{
- Size = new Vector2(30, 20)
+ Size = new Vector2(28, 14)
},
new OsuSpriteText
{
@@ -120,36 +126,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Font = OsuFont.GetFont(size: text_size),
Colour = score.Accuracy == 1 ? highAccuracyColour : Color4.White
},
- };
-
- var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: text_size)) { AutoSizeAxes = Axes.Both };
- username.AddUserLink(score.User);
-
- content.AddRange(new Drawable[]
- {
- new FillFlowContainer
+ new UpdateableFlag(score.User.Country)
{
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Margin = new MarginPadding { Right = horizontal_inset },
- Spacing = new Vector2(5, 0),
- Children = new Drawable[]
- {
- new UpdateableFlag(score.User.Country)
- {
- Size = new Vector2(20, 13),
- ShowPlaceholderOnNull = false,
- },
- username
- }
+ Size = new Vector2(19, 13),
+ ShowPlaceholderOnNull = false,
},
+ username,
new OsuSpriteText
{
Text = $@"{score.MaxCombo:N0}x",
Font = OsuFont.GetFont(size: text_size),
Colour = score.MaxCombo == score.Beatmap?.MaxCombo ? highAccuracyColour : Color4.White
}
- });
+ };
foreach (var kvp in score.SortedStatistics)
{
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs
index 83271efe09..d84e1eff8c 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTableRowBackground.cs
@@ -22,13 +22,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly int index;
private readonly ScoreInfo score;
- public ScoreTableRowBackground(int index, ScoreInfo score)
+ public ScoreTableRowBackground(int index, ScoreInfo score, float height)
{
this.index = index;
this.score = score;
RelativeSizeAxes = Axes.X;
- Height = 25;
+ Height = height;
CornerRadius = 5;
Masking = true;
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index 2d8bd10b13..7607eac1f8 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
@@ -5,7 +5,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics.UserInterface;
using osuTK;
using System.Linq;
using osu.Game.Online.API.Requests.Responses;
@@ -13,13 +12,14 @@ using osu.Game.Beatmaps;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Framework.Bindables;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
- public class ScoresContainer : CompositeDrawable
+ public class ScoresContainer : BeatmapSetLayoutSection
{
private const int spacing = 15;
@@ -31,10 +31,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly Box background;
private readonly ScoreTable scoreTable;
private readonly FillFlowContainer topScoresContainer;
- private readonly DimmedLoadingLayer loading;
+ private readonly LoadingLayer loading;
private readonly LeaderboardModSelector modSelector;
private readonly NoScoresPlaceholder noScoresPlaceholder;
- private readonly FillFlowContainer content;
private readonly NotSupporterPlaceholder notSupporterPlaceholder;
[Resolved]
@@ -76,23 +75,21 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public ScoresContainer()
{
- RelativeSizeAxes = Axes.X;
- AutoSizeAxes = Axes.Y;
- InternalChildren = new Drawable[]
+ AddRange(new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
- content = new FillFlowContainer
+ new FillFlowContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Width = 0.95f,
Direction = FillDirection.Vertical,
- Margin = new MarginPadding { Vertical = spacing },
+ Padding = new MarginPadding { Horizontal = 50 },
+ Margin = new MarginPadding { Vertical = 20 },
Children = new Drawable[]
{
new FillFlowContainer
@@ -121,7 +118,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
- Margin = new MarginPadding { Vertical = spacing },
+ Margin = new MarginPadding { Top = spacing },
Children = new Drawable[]
{
noScoresPlaceholder = new NoScoresPlaceholder
@@ -160,21 +157,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
}
}
},
- new Container
- {
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- CornerRadius = 5,
- Child = loading = new DimmedLoadingLayer(iconScale: 0.8f)
- {
- Alpha = 0,
- },
- }
+ loading = new LoadingLayer()
}
}
}
- },
- };
+ }
+ });
}
[BackgroundDependencyLoader]
@@ -232,7 +220,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending)
{
Scores = null;
- content.Hide();
+ Hide();
return;
}
@@ -246,7 +234,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
notSupporterPlaceholder.Hide();
- content.Show();
+ Show();
loading.Show();
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs
index a7066c4827..a15dc57d23 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private const float bottom_columns_min_width = 45;
private readonly FontUsage smallFont = OsuFont.GetFont(size: 16);
- private readonly FontUsage largeFont = OsuFont.GetFont(size: 22);
+ private readonly FontUsage largeFont = OsuFont.GetFont(size: 22, weight: FontWeight.Light);
private readonly TextColumn totalScoreColumn;
private readonly TextColumn accuracyColumn;
@@ -47,7 +47,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
- Spacing = new Vector2(10, 8),
Children = new Drawable[]
{
new FillFlowContainer
@@ -117,6 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public InfoColumn(string title, Drawable content, float? minWidth = null)
{
AutoSizeAxes = Axes.Both;
+ Margin = new MarginPadding { Vertical = 5 };
InternalChild = new GridContainer
{
@@ -128,7 +128,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
- new Dimension(GridSizeMode.Absolute, 4),
+ new Dimension(GridSizeMode.Absolute, 2),
new Dimension(GridSizeMode.AutoSize)
},
Content = new[]
@@ -138,21 +138,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
text = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold),
- Text = title.ToUpper()
+ Text = title.ToUpper(),
+ // 2px padding bottom + 1px vertical to compensate for the additional spacing because of 1.25 line-height in osu-web
+ Padding = new MarginPadding { Top = 1, Bottom = 3 }
}
},
new Drawable[]
{
separator = new Box
{
- Anchor = Anchor.CentreLeft,
+ Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.X,
- Height = 2
- }
+ Height = 2,
+ },
},
new[]
{
- content
+ // osu-web has 4px margin here but also uses 0.9 line-height, reducing margin to 2px seems like a good alternative to that
+ content.With(c => c.Margin = new MarginPadding { Top = 2 })
}
}
};
@@ -194,9 +197,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
public ModsInfoColumn()
: this(new FillFlowContainer
{
- AutoSizeAxes = Axes.Both,
+ AutoSizeAxes = Axes.X,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(1),
+ Height = 18f
})
{
}
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
index 9a67ea2b24..9111a0cfc7 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -12,7 +13,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Online.Leaderboards;
using osu.Game.Scoring;
using osu.Game.Users.Drawables;
-using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
@@ -24,7 +24,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private readonly UpdateableRank rank;
private readonly UpdateableAvatar avatar;
private readonly LinkFlowContainer usernameText;
- private readonly SpriteText date;
+ private readonly DrawableDate achievedOn;
private readonly UpdateableFlag flag;
public TopScoreUserSection()
@@ -67,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.Centre,
Size = new Vector2(70),
Masking = true,
- CornerRadius = 5,
+ CornerRadius = 4,
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
@@ -92,11 +92,24 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
},
- date = new OsuSpriteText
+ new FillFlowContainer
{
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
- Font = OsuFont.GetFont(size: 10)
+ Children = new[]
+ {
+ new OsuSpriteText
+ {
+ Text = "achieved ",
+ Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
+ },
+ achievedOn = new DrawableDate(DateTimeOffset.MinValue)
+ {
+ Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold)
+ },
+ }
},
flag = new UpdateableFlag
{
@@ -126,7 +139,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
avatar.User = value.User;
flag.Country = value.User.Country;
- date.Text = $@"achieved {HumanizerUtils.Humanize(value.Date)}";
+ achievedOn.Date = value.Date;
usernameText.Clear();
usernameText.AddUserLink(value.User);
diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs
index 15216b6e69..3bb36545cd 100644
--- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs
+++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Success Rate",
- Font = OsuFont.GetFont(size: 13)
+ Font = OsuFont.GetFont(size: 12)
},
successRate = new Bar
{
@@ -82,7 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopCentre,
- Font = OsuFont.GetFont(size: 13),
+ Font = OsuFont.GetFont(size: 12),
},
},
new OsuSpriteText
@@ -90,7 +90,7 @@ namespace osu.Game.Overlays.BeatmapSet
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = "Points of Failure",
- Font = OsuFont.GetFont(size: 13),
+ Font = OsuFont.GetFont(size: 12),
Margin = new MarginPadding { Vertical = 20 },
},
},
diff --git a/osu.Game/Overlays/BeatmapSetOverlay.cs b/osu.Game/Overlays/BeatmapSetOverlay.cs
index d29997f7e5..0d16c4842d 100644
--- a/osu.Game/Overlays/BeatmapSetOverlay.cs
+++ b/osu.Game/Overlays/BeatmapSetOverlay.cs
@@ -13,6 +13,7 @@ using osu.Game.Graphics.Containers;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.BeatmapSet;
using osu.Game.Overlays.BeatmapSet.Scores;
+using osu.Game.Overlays.Comments;
using osu.Game.Rulesets;
using osuTK;
@@ -40,6 +41,7 @@ namespace osu.Game.Overlays
{
OsuScrollContainer scroll;
Info info;
+ CommentsSection comments;
Children = new Drawable[]
{
@@ -51,29 +53,33 @@ namespace osu.Game.Overlays
{
RelativeSizeAxes = Axes.Both,
ScrollbarVisible = false,
- Child = new ReverseChildIDFillFlowContainer
+ Child = new ReverseChildIDFillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 20),
- Children = new Drawable[]
+ Children = new[]
{
- new ReverseChildIDFillFlowContainer
+ new BeatmapSetLayoutSection
{
- AutoSizeAxes = Axes.Y,
- RelativeSizeAxes = Axes.X,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ Child = new ReverseChildIDFillFlowContainer
{
- Header = new Header(),
- info = new Info()
- }
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ Header = new Header(),
+ info = new Info()
+ }
+ },
},
new ScoresContainer
{
Beatmap = { BindTarget = Header.Picker.Beatmap }
- }
+ },
+ comments = new CommentsSection()
},
},
},
@@ -81,6 +87,7 @@ namespace osu.Game.Overlays
Header.BeatmapSet.BindTo(beatmapSet);
info.BeatmapSet.BindTo(beatmapSet);
+ comments.BeatmapSet.BindTo(beatmapSet);
Header.Picker.Beatmap.ValueChanged += b =>
{
@@ -143,5 +150,30 @@ namespace osu.Game.Overlays
beatmapSet.Value = set;
Show();
}
+
+ private class CommentsSection : BeatmapSetLayoutSection
+ {
+ public readonly Bindable BeatmapSet = new Bindable();
+
+ public CommentsSection()
+ {
+ CommentsContainer comments;
+
+ Add(comments = new CommentsContainer());
+
+ BeatmapSet.BindValueChanged(beatmapSet =>
+ {
+ if (beatmapSet.NewValue?.OnlineBeatmapSetID is int onlineBeatmapSetID)
+ {
+ Show();
+ comments.ShowComments(CommentableType.Beatmapset, onlineBeatmapSetID);
+ }
+ else
+ {
+ Hide();
+ }
+ }, true);
+ }
+ }
}
}
diff --git a/osu.Game/Overlays/Changelog/ChangelogBuild.cs b/osu.Game/Overlays/Changelog/ChangelogBuild.cs
index 5a3ce6291e..8aee76cb08 100644
--- a/osu.Game/Overlays/Changelog/ChangelogBuild.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogBuild.cs
@@ -16,6 +16,7 @@ using osuTK.Graphics;
using osu.Framework.Allocation;
using System.Net;
using osuTK;
+using osu.Framework.Extensions.Color4Extensions;
namespace osu.Game.Overlays.Changelog
{
@@ -51,28 +52,27 @@ namespace osu.Game.Overlays.Changelog
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OsuColour colours, OverlayColourProvider colourProvider)
{
foreach (var categoryEntries in Build.ChangelogEntries.GroupBy(b => b.Category).OrderBy(c => c.Key))
{
ChangelogEntries.Add(new OsuSpriteText
{
Text = categoryEntries.Key,
- Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 24),
+ Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 18),
Margin = new MarginPadding { Top = 35, Bottom = 15 },
});
- var fontLarge = OsuFont.GetFont(size: 18);
- var fontMedium = OsuFont.GetFont(size: 14);
- var fontSmall = OsuFont.GetFont(size: 12);
+ var fontLarge = OsuFont.GetFont(size: 16);
+ var fontMedium = OsuFont.GetFont(size: 12);
- foreach (APIChangelogEntry entry in categoryEntries)
+ foreach (var entry in categoryEntries)
{
var entryColour = entry.Major ? colours.YellowLight : Color4.White;
LinkFlowContainer title;
- Container titleContainer = new Container
+ var titleContainer = new Container
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
@@ -83,9 +83,9 @@ namespace osu.Game.Overlays.Changelog
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreRight,
- Size = new Vector2(fontSmall.Size),
+ Size = new Vector2(10),
Icon = entry.Type == ChangelogEntryType.Fix ? FontAwesome.Solid.Check : FontAwesome.Solid.Plus,
- Colour = entryColour,
+ Colour = entryColour.Opacity(0.5f),
Margin = new MarginPadding { Right = 5 },
},
title = new LinkFlowContainer
@@ -123,10 +123,11 @@ namespace osu.Game.Overlays.Changelog
});
}
- title.AddText(" by ", t =>
+ title.AddText("by ", t =>
{
- t.Font = fontMedium;
+ t.Font = fontMedium.With(italics: true);
t.Colour = entryColour;
+ t.Padding = new MarginPadding { Left = 10 };
});
if (entry.GithubUser.UserId != null)
@@ -137,7 +138,7 @@ namespace osu.Game.Overlays.Changelog
Id = entry.GithubUser.UserId.Value
}, t =>
{
- t.Font = fontMedium;
+ t.Font = fontMedium.With(italics: true);
t.Colour = entryColour;
});
}
@@ -145,7 +146,7 @@ namespace osu.Game.Overlays.Changelog
{
title.AddLink(entry.GithubUser.DisplayName, entry.GithubUser.GithubUrl, t =>
{
- t.Font = fontMedium;
+ t.Font = fontMedium.With(italics: true);
t.Colour = entryColour;
});
}
@@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Changelog
{
title.AddText(entry.GithubUser.DisplayName, t =>
{
- t.Font = fontSmall;
+ t.Font = fontMedium.With(italics: true);
t.Colour = entryColour;
});
}
@@ -162,7 +163,7 @@ namespace osu.Game.Overlays.Changelog
if (!string.IsNullOrEmpty(entry.MessageHtml))
{
- TextFlowContainer message = new TextFlowContainer
+ var message = new TextFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
@@ -171,8 +172,8 @@ namespace osu.Game.Overlays.Changelog
// todo: use markdown parsing once API returns markdown
message.AddText(WebUtility.HtmlDecode(Regex.Replace(entry.MessageHtml, @"<(.|\n)*?>", string.Empty)), t =>
{
- t.Font = fontSmall;
- t.Colour = new Color4(235, 184, 254, 255);
+ t.Font = fontMedium;
+ t.Colour = colourProvider.Foreground1;
});
ChangelogEntries.Add(message);
diff --git a/osu.Game/Overlays/Changelog/ChangelogContent.cs b/osu.Game/Overlays/Changelog/ChangelogContent.cs
index f8d5bbd66c..49dd9bb835 100644
--- a/osu.Game/Overlays/Changelog/ChangelogContent.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogContent.cs
@@ -19,7 +19,6 @@ namespace osu.Game.Overlays.Changelog
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
- Padding = new MarginPadding { Bottom = 100 };
}
}
}
diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs
index 8663ec586b..dcadbf4cf5 100644
--- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs
@@ -4,9 +4,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;
@@ -22,6 +24,8 @@ namespace osu.Game.Overlays.Changelog
private const string listing_string = "listing";
+ private Box streamsBackground;
+
public ChangelogHeader()
{
TabControl.AddItem(listing_string);
@@ -40,6 +44,12 @@ namespace osu.Game.Overlays.Changelog
};
}
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ streamsBackground.Colour = colourProvider.Background5;
+ }
+
private ChangelogHeaderTitle title;
private void showBuild(ValueChangedEvent e)
@@ -72,7 +82,21 @@ namespace osu.Game.Overlays.Changelog
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
- Streams = new UpdateStreamBadgeArea(),
+ streamsBackground = new Box
+ {
+ RelativeSizeAxes = Axes.Both
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = new MarginPadding
+ {
+ Horizontal = 65,
+ Vertical = 20
+ },
+ Child = Streams = new UpdateStreamBadgeArea()
+ }
}
};
diff --git a/osu.Game/Overlays/Changelog/ChangelogListing.cs b/osu.Game/Overlays/Changelog/ChangelogListing.cs
index 41d8228475..9b74a8da6d 100644
--- a/osu.Game/Overlays/Changelog/ChangelogListing.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogListing.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests.Responses;
-using osuTK.Graphics;
namespace osu.Game.Overlays.Changelog
{
@@ -24,13 +23,13 @@ namespace osu.Game.Overlays.Changelog
}
[BackgroundDependencyLoader]
- private void load()
+ private void load(OverlayColourProvider colourProvider)
{
- DateTime currentDate = DateTime.MinValue;
+ var currentDate = DateTime.MinValue;
if (entries == null) return;
- foreach (APIChangelogBuild build in entries)
+ foreach (var build in entries)
{
if (build.CreatedAt.Date != currentDate)
{
@@ -40,7 +39,7 @@ namespace osu.Game.Overlays.Changelog
{
RelativeSizeAxes = Axes.X,
Height = 2,
- Colour = new Color4(17, 17, 17, 255),
+ Colour = colourProvider.Background6,
Margin = new MarginPadding { Top = 30 },
});
}
@@ -49,10 +48,9 @@ namespace osu.Game.Overlays.Changelog
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
- Margin = new MarginPadding { Top = 15 },
- Text = build.CreatedAt.Date.ToString("dd MMM yyyy"),
+ Margin = new MarginPadding { Top = 20 },
+ Text = build.CreatedAt.Date.ToString("dd MMMM yyyy"),
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 24),
- Colour = OsuColour.FromHex(@"FD5"),
});
currentDate = build.CreatedAt.Date;
@@ -68,7 +66,7 @@ namespace osu.Game.Overlays.Changelog
Child = new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = new Color4(32, 24, 35, 255),
+ Colour = colourProvider.Background6,
}
});
}
diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
index 67bcb6f558..8b89d63aab 100644
--- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@@ -16,6 +17,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Overlays.Comments;
using osuTK;
namespace osu.Game.Overlays.Changelog
@@ -30,7 +32,7 @@ namespace osu.Game.Overlays.Changelog
}
[BackgroundDependencyLoader]
- private void load(CancellationToken? cancellation, IAPIProvider api)
+ private void load(CancellationToken? cancellation, IAPIProvider api, OverlayColourProvider colourProvider)
{
bool complete = false;
@@ -57,11 +59,22 @@ namespace osu.Game.Overlays.Changelog
if (build != null)
{
+ CommentsContainer comments;
+
Children = new Drawable[]
{
new ChangelogBuildWithNavigation(build) { SelectBuild = SelectBuild },
- new Comments(build)
+ new Box
+ {
+ RelativeSizeAxes = Axes.X,
+ Height = 2,
+ Colour = colourProvider.Background6,
+ Margin = new MarginPadding { Top = 30 },
+ },
+ comments = new CommentsContainer()
};
+
+ comments.ShowComments(CommentableType.Build, build.Id);
}
}
@@ -72,6 +85,8 @@ namespace osu.Game.Overlays.Changelog
{
}
+ private OsuSpriteText date;
+
protected override FillFlowContainer CreateHeader()
{
var fill = base.CreateHeader();
@@ -81,11 +96,10 @@ namespace osu.Game.Overlays.Changelog
existing.Scale = new Vector2(1.25f);
existing.Action = null;
- existing.Add(new OsuSpriteText
+ existing.Add(date = new OsuSpriteText
{
- Text = Build.CreatedAt.Date.ToString("dd MMM yyyy"),
+ Text = Build.CreatedAt.Date.ToString("dd MMMM yyyy"),
Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 14),
- Colour = OsuColour.FromHex(@"FD5"),
Anchor = Anchor.BottomCentre,
Origin = Anchor.TopCentre,
Margin = new MarginPadding { Top = 5 },
@@ -105,6 +119,12 @@ namespace osu.Game.Overlays.Changelog
return fill;
}
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ date.Colour = colourProvider.Light1;
+ }
}
private class NavigationIconButton : IconButton
diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs b/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs
index 52b77604d9..6786bbc49f 100644
--- a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs
+++ b/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs
@@ -3,8 +3,6 @@
using Humanizer;
using osu.Framework.Allocation;
-using osu.Framework.Audio;
-using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -16,99 +14,81 @@ using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Overlays.Changelog
{
public class UpdateStreamBadge : TabItem
{
- private const float badge_height = 66.5f;
private const float badge_width = 100;
private const float transition_duration = 100;
- private readonly ExpandingBar expandingBar;
- private SampleChannel sampleClick;
- private SampleChannel sampleHover;
-
- private readonly FillFlowContainer text;
-
public readonly Bindable SelectedTab = new Bindable();
- private readonly Container fadeContainer;
+ private readonly APIUpdateStream stream;
+
+ private FillFlowContainer text;
+ private ExpandingBar expandingBar;
public UpdateStreamBadge(APIUpdateStream stream)
: base(stream)
{
- Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, badge_height);
- Padding = new MarginPadding(5);
-
- Child = fadeContainer = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- text = new FillFlowContainer
- {
- AutoSizeAxes = Axes.X,
- RelativeSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new[]
- {
- new OsuSpriteText
- {
- Text = stream.DisplayName,
- Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 12),
- Margin = new MarginPadding { Top = 6 },
- },
- new OsuSpriteText
- {
- Text = stream.LatestBuild.DisplayVersion,
- Font = OsuFont.GetFont(weight: FontWeight.Light, size: 16),
- },
- new OsuSpriteText
- {
- Text = stream.LatestBuild.Users > 0 ? $"{stream.LatestBuild.Users:N0} {"user".Pluralize(stream.LatestBuild.Users == 1)} online" : null,
- Font = OsuFont.GetFont(weight: FontWeight.Regular, size: 10),
- Colour = new Color4(203, 164, 218, 255),
- },
- }
- },
- expandingBar = new ExpandingBar
- {
- Anchor = Anchor.TopCentre,
- Colour = stream.Colour,
- ExpandedSize = 4,
- CollapsedSize = 2,
- IsCollapsed = true
- },
- }
- };
-
- SelectedTab.BindValueChanged(_ => updateState(), true);
+ this.stream = stream;
}
[BackgroundDependencyLoader]
- private void load(AudioManager audio)
+ private void load(OverlayColourProvider colourProvider)
{
- sampleClick = audio.Samples.Get(@"UI/generic-select-soft");
- sampleHover = audio.Samples.Get(@"UI/generic-hover-soft");
+ Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60);
+ Padding = new MarginPadding(5);
+
+ AddRange(new Drawable[]
+ {
+ text = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Margin = new MarginPadding { Top = 6 },
+ Children = new[]
+ {
+ new OsuSpriteText
+ {
+ Text = stream.DisplayName,
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black),
+ },
+ new OsuSpriteText
+ {
+ Text = stream.LatestBuild.DisplayVersion,
+ Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
+ },
+ new OsuSpriteText
+ {
+ Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null,
+ Font = OsuFont.GetFont(size: 10),
+ Colour = colourProvider.Foreground1
+ },
+ }
+ },
+ expandingBar = new ExpandingBar
+ {
+ Anchor = Anchor.TopCentre,
+ Colour = stream.Colour,
+ ExpandedSize = 4,
+ CollapsedSize = 2,
+ Expanded = true
+ },
+ new HoverClickSounds()
+ });
+
+ SelectedTab.BindValueChanged(_ => updateState(), true);
}
protected override void OnActivated() => updateState();
protected override void OnDeactivated() => updateState();
- protected override bool OnClick(ClickEvent e)
- {
- sampleClick?.Play();
- return base.OnClick(e);
- }
-
protected override bool OnHover(HoverEvent e)
{
- sampleHover?.Play();
updateState();
-
return base.OnHover(e);
}
@@ -120,38 +100,41 @@ namespace osu.Game.Overlays.Changelog
private void updateState()
{
- // Expand based on the local state
- bool shouldExpand = Active.Value || IsHovered;
+ // highlighted regardless if we are hovered
+ bool textHighlighted = IsHovered;
+ bool barExpanded = IsHovered;
- // Expand based on whether no build is selected and the badge area is hovered
- shouldExpand |= SelectedTab.Value == null && !externalDimRequested;
-
- if (shouldExpand)
+ if (SelectedTab.Value == null)
{
- expandingBar.Expand();
- fadeContainer.FadeTo(1, transition_duration);
+ // at listing, all badges are highlighted when user is not hovering any badge.
+ textHighlighted |= !userHoveringArea;
+ barExpanded |= !userHoveringArea;
}
else
{
- expandingBar.Collapse();
- fadeContainer.FadeTo(0.5f, transition_duration);
+ // bar is always expanded when active
+ barExpanded |= Active.Value;
+
+ // text is highlighted only when hovered or active (but not if in selection mode)
+ textHighlighted |= Active.Value && !userHoveringArea;
}
- text.FadeTo(externalDimRequested && !IsHovered ? 0.5f : 1, transition_duration);
+ expandingBar.Expanded = barExpanded;
+ text.FadeTo(textHighlighted ? 1 : 0.5f, transition_duration, Easing.OutQuint);
}
- private bool externalDimRequested;
+ private bool userHoveringArea;
- public void EnableDim()
+ public bool UserHoveringArea
{
- externalDimRequested = true;
- updateState();
- }
+ set
+ {
+ if (value == userHoveringArea)
+ return;
- public void DisableDim()
- {
- externalDimRequested = false;
- updateState();
+ userHoveringArea = value;
+ updateState();
+ }
}
}
}
diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs b/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs
index ca57ba24e2..ffb622dd37 100644
--- a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs
+++ b/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs
@@ -6,9 +6,7 @@ using osu.Framework.Input.Events;
using osu.Game.Online.API.Requests.Responses;
using System.Collections.Generic;
using System.Linq;
-using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
-using osuTK.Graphics;
namespace osu.Game.Overlays.Changelog
{
@@ -18,52 +16,36 @@ namespace osu.Game.Overlays.Changelog
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
-
- AddInternal(new Box
- {
- Colour = Color4.Black,
- Alpha = 0.12f,
- RelativeSizeAxes = Axes.Both,
- });
}
public void Populate(List streams)
{
- foreach (APIUpdateStream updateStream in streams)
+ foreach (var updateStream in streams)
AddItem(updateStream);
}
protected override bool OnHover(HoverEvent e)
{
- foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType())
- streamBadge.EnableDim();
+ foreach (var streamBadge in TabContainer.Children.OfType())
+ streamBadge.UserHoveringArea = true;
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
- foreach (UpdateStreamBadge streamBadge in TabContainer.Children.OfType())
- streamBadge.DisableDim();
+ foreach (var streamBadge in TabContainer.Children.OfType())
+ streamBadge.UserHoveringArea = false;
base.OnHoverLost(e);
}
- protected override TabFillFlowContainer CreateTabFlow()
+ protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
{
- var flow = base.CreateTabFlow();
-
- flow.RelativeSizeAxes = Axes.X;
- flow.AutoSizeAxes = Axes.Y;
- flow.AllowMultiline = true;
- flow.Padding = new MarginPadding
- {
- Vertical = 20,
- Horizontal = 85,
- };
-
- return flow;
- }
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ AllowMultiline = true,
+ };
protected override Dropdown CreateDropdown() => null;
diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs
index 6a8cb29d3e..d13ac5c2de 100644
--- a/osu.Game/Overlays/ChangelogOverlay.cs
+++ b/osu.Game/Overlays/ChangelogOverlay.cs
@@ -13,7 +13,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
using osu.Game.Online.API.Requests;
@@ -42,14 +41,14 @@ namespace osu.Game.Overlays
}
[BackgroundDependencyLoader]
- private void load(AudioManager audio, OsuColour colour)
+ private void load(AudioManager audio)
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = colour.PurpleDarkAlternative,
+ Colour = ColourProvider.Background4,
},
new OsuScrollContainer
{
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index bdc241a437..34afc3c431 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Overlays
private readonly List loadedChannels = new List();
- private LoadingAnimation loading;
+ private LoadingSpinner loading;
private FocusedTextBox textbox;
@@ -146,7 +146,7 @@ namespace osu.Game.Overlays
}
}
},
- loading = new LoadingAnimation(),
+ loading = new LoadingSpinner(),
}
},
tabsArea = new TabsArea
diff --git a/osu.Game/Overlays/Comments/CancellableCommentEditor.cs b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs
new file mode 100644
index 0000000000..c226b7f07f
--- /dev/null
+++ b/osu.Game/Overlays/Comments/CancellableCommentEditor.cs
@@ -0,0 +1,71 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+
+namespace osu.Game.Overlays.Comments
+{
+ public abstract class CancellableCommentEditor : CommentEditor
+ {
+ public Action OnCancel;
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ButtonsContainer.Add(new CancelButton
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Action = () => OnCancel?.Invoke()
+ });
+ }
+
+ private class CancelButton : OsuHoverContainer
+ {
+ protected override IEnumerable EffectTargets => new[] { background };
+
+ private readonly Box background;
+
+ public CancelButton()
+ {
+ AutoSizeAxes = Axes.Both;
+ Child = new CircularContainer
+ {
+ Masking = true,
+ Height = 25,
+ AutoSizeAxes = Axes.X,
+ Children = new Drawable[]
+ {
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
+ Margin = new MarginPadding { Horizontal = 20 },
+ Text = @"Cancel"
+ }
+ }
+ };
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ IdleColour = colourProvider.Light4;
+ HoverColour = colourProvider.Light3;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Comments/CommentEditor.cs b/osu.Game/Overlays/Comments/CommentEditor.cs
new file mode 100644
index 0000000000..2fa4cb68f3
--- /dev/null
+++ b/osu.Game/Overlays/Comments/CommentEditor.cs
@@ -0,0 +1,241 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Graphics.Sprites;
+using osuTK.Graphics;
+using osu.Game.Graphics.UserInterface;
+using System.Collections.Generic;
+using System;
+using osuTK;
+using osu.Framework.Bindables;
+
+namespace osu.Game.Overlays.Comments
+{
+ public abstract class CommentEditor : CompositeDrawable
+ {
+ private const int side_padding = 8;
+
+ public Action OnCommit;
+
+ public bool IsLoading
+ {
+ get => commitButton.IsLoading;
+ set => commitButton.IsLoading = value;
+ }
+
+ protected abstract string FooterText { get; }
+
+ protected abstract string CommitButtonText { get; }
+
+ protected abstract string TextBoxPlaceholder { get; }
+
+ protected FillFlowContainer ButtonsContainer { get; private set; }
+
+ protected readonly Bindable Current = new Bindable();
+
+ private CommitButton commitButton;
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ EditorTextBox textBox;
+
+ RelativeSizeAxes = Axes.X;
+ AutoSizeAxes = Axes.Y;
+ Masking = true;
+ CornerRadius = 6;
+ BorderThickness = 3;
+ BorderColour = colourProvider.Background3;
+
+ AddRangeInternal(new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colourProvider.Background3
+ },
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Y,
+ RelativeSizeAxes = Axes.X,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
+ {
+ textBox = new EditorTextBox
+ {
+ Height = 40,
+ RelativeSizeAxes = Axes.X,
+ PlaceholderText = TextBoxPlaceholder,
+ Current = Current
+ },
+ new Container
+ {
+ Name = "Footer",
+ RelativeSizeAxes = Axes.X,
+ Height = 35,
+ Padding = new MarginPadding { Horizontal = side_padding },
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold),
+ Text = FooterText
+ },
+ ButtonsContainer = new FillFlowContainer
+ {
+ Name = "Buttons",
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(5, 0),
+ Child = commitButton = new CommitButton(CommitButtonText)
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Action = () =>
+ {
+ OnCommit?.Invoke(Current.Value);
+ Current.Value = string.Empty;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ });
+
+ textBox.OnCommit += (u, v) =>
+ {
+ if (commitButton.IsBlocked.Value)
+ return;
+
+ commitButton.Click();
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Current.BindValueChanged(text => commitButton.IsBlocked.Value = string.IsNullOrEmpty(text.NewValue), true);
+ }
+
+ private class EditorTextBox : BasicTextBox
+ {
+ protected override float LeftRightPadding => side_padding;
+
+ protected override Color4 SelectionColour => Color4.Gray;
+
+ private OsuSpriteText placeholder;
+
+ public EditorTextBox()
+ {
+ Masking = false;
+ TextContainer.Height = 0.4f;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ BackgroundUnfocused = BackgroundFocused = colourProvider.Background5;
+ placeholder.Colour = colourProvider.Background3;
+ BackgroundCommit = colourProvider.Background3;
+ }
+
+ protected override SpriteText CreatePlaceholder() => placeholder = new OsuSpriteText
+ {
+ Font = OsuFont.GetFont(weight: FontWeight.Regular),
+ };
+
+ protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) };
+ }
+
+ private class CommitButton : LoadingButton
+ {
+ private const int duration = 200;
+
+ public readonly BindableBool IsBlocked = new BindableBool();
+
+ public override bool PropagatePositionalInputSubTree => !IsBlocked.Value && base.PropagatePositionalInputSubTree;
+
+ protected override IEnumerable EffectTargets => new[] { background };
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
+ private OsuSpriteText drawableText;
+ private Box background;
+ private Box blockedBackground;
+
+ public CommitButton(string text)
+ {
+ AutoSizeAxes = Axes.Both;
+ LoadingAnimationSize = new Vector2(10);
+
+ drawableText.Text = text;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ IdleColour = colourProvider.Light4;
+ HoverColour = colourProvider.Light3;
+ blockedBackground.Colour = colourProvider.Background5;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ IsBlocked.BindValueChanged(onBlockedStateChanged, true);
+ }
+
+ private void onBlockedStateChanged(ValueChangedEvent isBlocked)
+ {
+ drawableText.FadeColour(isBlocked.NewValue ? colourProvider.Foreground1 : Color4.White, duration, Easing.OutQuint);
+ background.FadeTo(isBlocked.NewValue ? 0 : 1, duration, Easing.OutQuint);
+ }
+
+ protected override Drawable CreateContent() => new CircularContainer
+ {
+ Masking = true,
+ Height = 25,
+ AutoSizeAxes = Axes.X,
+ Children = new Drawable[]
+ {
+ blockedBackground = new Box
+ {
+ RelativeSizeAxes = Axes.Both
+ },
+ background = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Alpha = 0
+ },
+ drawableText = new OsuSpriteText
+ {
+ AlwaysPresent = true,
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
+ Margin = new MarginPadding { Horizontal = 20 }
+ }
+ }
+ };
+
+ protected override void OnLoadStarted() => drawableText.FadeOut(duration, Easing.OutQuint);
+
+ protected override void OnLoadFinished() => drawableText.FadeIn(duration, Easing.OutQuint);
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs
index 33a6be0d7a..591a9dc86e 100644
--- a/osu.Game/Overlays/Comments/CommentsContainer.cs
+++ b/osu.Game/Overlays/Comments/CommentsContainer.cs
@@ -18,8 +18,8 @@ namespace osu.Game.Overlays.Comments
{
public class CommentsContainer : CompositeDrawable
{
- private CommentableType type;
- private long? id;
+ private readonly Bindable type = new Bindable();
+ private readonly BindableLong id = new BindableLong();
public readonly Bindable Sort = new Bindable();
public readonly BindableBool ShowDeleted = new BindableBool();
@@ -127,8 +127,8 @@ namespace osu.Game.Overlays.Comments
/// The id of the resource to get comments for.
public void ShowComments(CommentableType type, long id)
{
- this.type = type;
- this.id = id;
+ this.type.Value = type;
+ this.id.Value = id;
if (!IsLoaded)
return;
@@ -147,12 +147,12 @@ namespace osu.Game.Overlays.Comments
private void getComments()
{
- if (!id.HasValue)
+ if (id.Value <= 0)
return;
request?.Cancel();
loadCancellation?.Cancel();
- request = new GetCommentsRequest(type, id.Value, Sort.Value, currentPage++);
+ request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0);
request.Success += onSuccess;
api.PerformAsync(request);
}
@@ -172,7 +172,10 @@ namespace osu.Game.Overlays.Comments
LoadComponentAsync(new CommentsPage(response)
{
- ShowDeleted = { BindTarget = ShowDeleted }
+ ShowDeleted = { BindTarget = ShowDeleted },
+ Sort = { BindTarget = Sort },
+ Type = { BindTarget = type },
+ CommentableId = { BindTarget = id }
}, loaded =>
{
content.Add(loaded);
diff --git a/osu.Game/Overlays/Comments/CommentsHeader.cs b/osu.Game/Overlays/Comments/CommentsHeader.cs
index 1aa40201f1..83f44ccd80 100644
--- a/osu.Game/Overlays/Comments/CommentsHeader.cs
+++ b/osu.Game/Overlays/Comments/CommentsHeader.cs
@@ -109,6 +109,7 @@ namespace osu.Game.Overlays.Comments
public enum CommentsSortCriteria
{
+ [System.ComponentModel.Description(@"Recent")]
New,
Old,
Top
diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs
index 153ce676eb..9b146b0a7d 100644
--- a/osu.Game/Overlays/Comments/CommentsPage.cs
+++ b/osu.Game/Overlays/Comments/CommentsPage.cs
@@ -9,14 +9,25 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Sprites;
using System.Linq;
+using osu.Game.Online.API.Requests;
+using osu.Game.Online.API;
+using System.Collections.Generic;
+using JetBrains.Annotations;
namespace osu.Game.Overlays.Comments
{
public class CommentsPage : CompositeDrawable
{
public readonly BindableBool ShowDeleted = new BindableBool();
+ public readonly Bindable Sort = new Bindable();
+ public readonly Bindable Type = new Bindable();
+ public readonly BindableLong CommentableId = new BindableLong();
+
+ [Resolved]
+ private IAPIProvider api { get; set; }
private readonly CommentBundle commentBundle;
+ private FillFlowContainer flow;
public CommentsPage(CommentBundle commentBundle)
{
@@ -26,8 +37,6 @@ namespace osu.Game.Overlays.Comments
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
- FillFlowContainer flow;
-
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
@@ -52,14 +61,74 @@ namespace osu.Game.Overlays.Comments
return;
}
- foreach (var c in commentBundle.Comments)
+ AppendComments(commentBundle);
+ }
+
+ private DrawableComment getDrawableComment(Comment comment)
+ {
+ if (CommentDictionary.TryGetValue(comment.Id, out var existing))
+ return existing;
+
+ return CommentDictionary[comment.Id] = new DrawableComment(comment)
{
- if (c.IsTopLevel)
+ ShowDeleted = { BindTarget = ShowDeleted },
+ Sort = { BindTarget = Sort },
+ RepliesRequested = onCommentRepliesRequested
+ };
+ }
+
+ private void onCommentRepliesRequested(DrawableComment drawableComment, int page)
+ {
+ var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id);
+
+ request.Success += response => Schedule(() => AppendComments(response));
+
+ api.PerformAsync(request);
+ }
+
+ protected readonly Dictionary CommentDictionary = new Dictionary();
+
+ ///
+ /// Appends retrieved comments to the subtree rooted of comments in this page.
+ ///
+ /// The bundle of comments to add.
+ protected void AppendComments([NotNull] CommentBundle bundle)
+ {
+ var orphaned = new List();
+
+ foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments))
+ {
+ // Exclude possible duplicated comments.
+ if (CommentDictionary.ContainsKey(comment.Id))
+ continue;
+
+ addNewComment(comment);
+ }
+
+ // Comments whose parents were seen later than themselves can now be added.
+ foreach (var o in orphaned)
+ addNewComment(o);
+
+ void addNewComment(Comment comment)
+ {
+ var drawableComment = getDrawableComment(comment);
+
+ if (comment.ParentId == null)
{
- flow.Add(new DrawableComment(c)
- {
- ShowDeleted = { BindTarget = ShowDeleted }
- });
+ // Comments that have no parent are added as top-level comments to the flow.
+ flow.Add(drawableComment);
+ }
+ else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable))
+ {
+ // The comment's parent has already been seen, so the parent<-> child links can be added.
+ comment.ParentComment = parentDrawable.Comment;
+ parentDrawable.Replies.Add(drawableComment);
+ }
+ else
+ {
+ // The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order.
+ // Since this comment has now been seen, any further children can be added to it without being orphaned themselves.
+ orphaned.Add(comment);
}
}
}
diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs
index 70ea478814..46f600615a 100644
--- a/osu.Game/Overlays/Comments/DrawableComment.cs
+++ b/osu.Game/Overlays/Comments/DrawableComment.cs
@@ -12,11 +12,16 @@ using osu.Game.Graphics.Containers;
using osu.Game.Utils;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Bindables;
-using osu.Framework.Graphics.Shapes;
using System.Linq;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osu.Framework.Allocation;
+using osuTK.Graphics;
+using System.Collections.Generic;
+using System;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Extensions.IEnumerableExtensions;
+using System.Collections.Specialized;
namespace osu.Game.Overlays.Comments
{
@@ -25,24 +30,37 @@ namespace osu.Game.Overlays.Comments
private const int avatar_size = 40;
private const int margin = 10;
+ public Action RepliesRequested;
+
+ public readonly Comment Comment;
+
public readonly BindableBool ShowDeleted = new BindableBool();
+ public readonly Bindable Sort = new Bindable();
+ private readonly Dictionary loadedReplies = new Dictionary();
+
+ public readonly BindableList Replies = new BindableList();
private readonly BindableBool childrenExpanded = new BindableBool(true);
+ private int currentPage;
+
private FillFlowContainer childCommentsVisibilityContainer;
- private readonly Comment comment;
+ private FillFlowContainer childCommentsContainer;
+ private LoadMoreCommentsButton loadMoreCommentsButton;
+ private ShowMoreButton showMoreButton;
+ private RepliesButton repliesButton;
+ private ChevronButton chevronButton;
+ private DeletedCommentsCounter deletedCommentsCounter;
public DrawableComment(Comment comment)
{
- this.comment = comment;
+ Comment = comment;
}
[BackgroundDependencyLoader]
private void load()
{
LinkFlowContainer username;
- FillFlowContainer childCommentsContainer;
- DeletedCommentsCounter deletedCommentsCounter;
FillFlowContainer info;
LinkFlowContainer message;
GridContainer content;
@@ -50,234 +68,296 @@ namespace osu.Game.Overlays.Comments
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
- InternalChild = new FillFlowContainer
+ InternalChildren = new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ new FillFlowContainer
{
- new Container
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding(margin) { Left = margin + 5 },
- Child = content = new GridContainer
+ new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- ColumnDimensions = new[]
+ Padding = new MarginPadding(margin) { Left = margin + 5 },
+ Child = content = new GridContainer
{
- new Dimension(GridSizeMode.AutoSize),
- new Dimension(),
- },
- RowDimensions = new[]
- {
- new Dimension(GridSizeMode.AutoSize)
- },
- Content = new[]
- {
- new Drawable[]
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ ColumnDimensions = new[]
{
- new FillFlowContainer
+ new Dimension(GridSizeMode.AutoSize),
+ new Dimension(),
+ },
+ RowDimensions = new[]
+ {
+ new Dimension(GridSizeMode.AutoSize)
+ },
+ Content = new[]
+ {
+ new Drawable[]
{
- AutoSizeAxes = Axes.Both,
- Margin = new MarginPadding { Horizontal = margin },
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(5, 0),
- Children = new Drawable[]
+ new FillFlowContainer
{
- new Container
+ AutoSizeAxes = Axes.Both,
+ Margin = new MarginPadding { Horizontal = margin },
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(5, 0),
+ Children = new Drawable[]
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Width = 40,
- AutoSizeAxes = Axes.Y,
- Child = votePill = new VotePill(comment)
+ new Container
{
- Anchor = Anchor.CentreRight,
- Origin = Anchor.CentreRight,
- }
- },
- new UpdateableAvatar(comment.User)
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Size = new Vector2(avatar_size),
- Masking = true,
- CornerRadius = avatar_size / 2f,
- CornerExponent = 2,
- },
- }
- },
- new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Spacing = new Vector2(0, 3),
- Children = new Drawable[]
- {
- new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(7, 0),
- Children = new Drawable[]
- {
- username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true))
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Width = 40,
+ AutoSizeAxes = Axes.Y,
+ Child = votePill = new VotePill(Comment)
{
- AutoSizeAxes = Axes.Both,
- },
- new ParentUsername(comment),
- new OsuSpriteText
- {
- Alpha = comment.IsDeleted ? 1 : 0,
- Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
- Text = @"deleted",
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
}
- }
- },
- message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14))
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Right = 40 }
- },
- info = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(10, 0),
- Colour = OsuColour.Gray(0.7f),
- Children = new Drawable[]
+ },
+ new UpdateableAvatar(Comment.User)
{
- new OsuSpriteText
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Size = new Vector2(avatar_size),
+ Masking = true,
+ CornerRadius = avatar_size / 2f,
+ CornerExponent = 2,
+ },
+ }
+ },
+ new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Spacing = new Vector2(0, 3),
+ Children = new Drawable[]
+ {
+ new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(7, 0),
+ Children = new Drawable[]
{
- Anchor = Anchor.CentreLeft,
- Origin = Anchor.CentreLeft,
- Font = OsuFont.GetFont(size: 12),
- Text = HumanizerUtils.Humanize(comment.CreatedAt)
- },
- new RepliesButton(comment.RepliesCount)
+ username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true))
+ {
+ AutoSizeAxes = Axes.Both,
+ },
+ new ParentUsername(Comment),
+ new OsuSpriteText
+ {
+ Alpha = Comment.IsDeleted ? 1 : 0,
+ Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
+ Text = @"deleted",
+ }
+ }
+ },
+ message = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14))
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = new MarginPadding { Right = 40 }
+ },
+ info = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(10, 0),
+ Children = new Drawable[]
{
- Expanded = { BindTarget = childrenExpanded }
- },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Font = OsuFont.GetFont(size: 12),
+ Colour = OsuColour.Gray(0.7f),
+ Text = HumanizerUtils.Humanize(Comment.CreatedAt)
+ },
+ repliesButton = new RepliesButton(Comment.RepliesCount)
+ {
+ Expanded = { BindTarget = childrenExpanded }
+ },
+ loadMoreCommentsButton = new LoadMoreCommentsButton
+ {
+ Action = () => RepliesRequested(this, ++currentPage)
+ }
+ }
}
}
}
}
}
}
- }
- },
- childCommentsVisibilityContainer = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ },
+ childCommentsVisibilityContainer = new FillFlowContainer
{
- childCommentsContainer = new FillFlowContainer
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- Padding = new MarginPadding { Left = 20 },
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical
- },
- deletedCommentsCounter = new DeletedCommentsCounter
- {
- ShowDeleted = { BindTarget = ShowDeleted }
+ childCommentsContainer = new FillFlowContainer
+ {
+ Padding = new MarginPadding { Left = 20 },
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical
+ },
+ deletedCommentsCounter = new DeletedCommentsCounter
+ {
+ ShowDeleted = { BindTarget = ShowDeleted }
+ },
+ showMoreButton = new ShowMoreButton
+ {
+ Action = () => RepliesRequested(this, ++currentPage)
+ }
}
- }
+ },
}
+ },
+ chevronButton = new ChevronButton
+ {
+ Anchor = Anchor.TopRight,
+ Origin = Anchor.TopRight,
+ Margin = new MarginPadding { Right = 30, Top = margin },
+ Expanded = { BindTarget = childrenExpanded },
+ Alpha = 0
}
};
- deletedCommentsCounter.Count.Value = comment.DeletedChildrenCount;
-
- if (comment.UserId.HasValue)
- username.AddUserLink(comment.User);
+ if (Comment.UserId.HasValue)
+ username.AddUserLink(Comment.User);
else
- username.AddText(comment.LegacyName);
+ username.AddText(Comment.LegacyName);
- if (comment.EditedAt.HasValue)
+ if (Comment.EditedAt.HasValue)
{
info.Add(new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 12),
- Text = $@"edited {HumanizerUtils.Humanize(comment.EditedAt.Value)} by {comment.EditedUser.Username}"
+ Text = $@"edited {HumanizerUtils.Humanize(Comment.EditedAt.Value)} by {Comment.EditedUser.Username}"
});
}
- if (comment.HasMessage)
+ if (Comment.HasMessage)
{
- var formattedSource = MessageFormatter.FormatText(comment.Message);
+ var formattedSource = MessageFormatter.FormatText(Comment.Message);
message.AddLinks(formattedSource.Text, formattedSource.Links);
}
- if (comment.IsDeleted)
+ if (Comment.IsDeleted)
{
content.FadeColour(OsuColour.Gray(0.5f));
votePill.Hide();
}
- if (comment.IsTopLevel)
+ if (Comment.IsTopLevel)
{
- AddInternal(new Container
+ AddInternal(new Box
{
- RelativeSizeAxes = Axes.X,
- Height = 1.5f,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
- Child = new Box
- {
- RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.Gray(0.1f)
- }
+ RelativeSizeAxes = Axes.X,
+ Height = 1.5f,
+ Colour = OsuColour.Gray(0.1f)
});
-
- if (comment.ChildComments.Any())
- {
- AddInternal(new ChevronButton(comment)
- {
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- Margin = new MarginPadding { Right = 30, Top = margin },
- Expanded = { BindTarget = childrenExpanded }
- });
- }
}
- comment.ChildComments.ForEach(c => childCommentsContainer.Add(new DrawableComment(c)
+ if (Replies.Any())
+ onRepliesAdded(Replies);
+
+ Replies.CollectionChanged += (_, args) =>
{
- ShowDeleted = { BindTarget = ShowDeleted }
- }));
+ switch (args.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ onRepliesAdded(args.NewItems.Cast());
+ break;
+
+ default:
+ throw new NotSupportedException(@"You can only add replies to this list. Other actions are not supported.");
+ }
+ };
}
protected override void LoadComplete()
{
ShowDeleted.BindValueChanged(show =>
{
- if (comment.IsDeleted)
+ if (Comment.IsDeleted)
this.FadeTo(show.NewValue ? 1 : 0);
}, true);
childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true);
+
+ updateButtonsState();
+
base.LoadComplete();
}
+ public bool ContainsReply(long replyId) => loadedReplies.ContainsKey(replyId);
+
+ private void onRepliesAdded(IEnumerable replies)
+ {
+ var page = createRepliesPage(replies);
+
+ if (LoadState == LoadState.Loading)
+ {
+ addRepliesPage(page, replies);
+ return;
+ }
+
+ LoadComponentAsync(page, loaded => addRepliesPage(loaded, replies));
+ }
+
+ private void addRepliesPage(FillFlowContainer page, IEnumerable replies)
+ {
+ childCommentsContainer.Add(page);
+
+ var newReplies = replies.Select(reply => reply.Comment);
+ newReplies.ForEach(reply => loadedReplies.Add(reply.Id, reply));
+ deletedCommentsCounter.Count.Value += newReplies.Count(reply => reply.IsDeleted);
+ updateButtonsState();
+ }
+
+ private FillFlowContainer createRepliesPage(IEnumerable replies) => new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Direction = FillDirection.Vertical,
+ Children = replies.ToList()
+ };
+
+ private void updateButtonsState()
+ {
+ var loadedReplesCount = loadedReplies.Count;
+ var hasUnloadedReplies = loadedReplesCount != Comment.RepliesCount;
+
+ loadMoreCommentsButton.FadeTo(hasUnloadedReplies && loadedReplesCount == 0 ? 1 : 0);
+ showMoreButton.FadeTo(hasUnloadedReplies && loadedReplesCount > 0 ? 1 : 0);
+ repliesButton.FadeTo(loadedReplesCount != 0 ? 1 : 0);
+
+ if (Comment.IsTopLevel)
+ chevronButton.FadeTo(loadedReplesCount != 0 ? 1 : 0);
+
+ showMoreButton.IsLoading = loadMoreCommentsButton.IsLoading = false;
+ }
+
private class ChevronButton : ShowChildrenButton
{
private readonly SpriteIcon icon;
- public ChevronButton(Comment comment)
+ public ChevronButton()
{
- Alpha = comment.IsTopLevel && comment.ChildComments.Any() ? 1 : 0;
Child = icon = new SpriteIcon
{
Size = new Vector2(12),
- Colour = OsuColour.Gray(0.7f)
};
}
@@ -296,7 +376,6 @@ namespace osu.Game.Overlays.Comments
{
this.count = count;
- Alpha = count == 0 ? 0 : 1;
Child = text = new OsuSpriteText
{
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
@@ -305,10 +384,34 @@ namespace osu.Game.Overlays.Comments
protected override void OnExpandedChanged(ValueChangedEvent expanded)
{
- text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})";
+ text.Text = $@"{(expanded.NewValue ? "[-]" : "[+]")} replies ({count})";
}
}
+ private class LoadMoreCommentsButton : GetCommentRepliesButton
+ {
+ public LoadMoreCommentsButton()
+ {
+ IdleColour = OsuColour.Gray(0.7f);
+ HoverColour = Color4.White;
+ }
+
+ protected override string GetText() => @"[+] load replies";
+ }
+
+ private class ShowMoreButton : GetCommentRepliesButton
+ {
+ [BackgroundDependencyLoader]
+ private void load(OverlayColourProvider colourProvider)
+ {
+ Margin = new MarginPadding { Vertical = 10, Left = 80 };
+ IdleColour = colourProvider.Light2;
+ HoverColour = colourProvider.Light1;
+ }
+
+ protected override string GetText() => @"Show More";
+ }
+
private class ParentUsername : FillFlowContainer, IHasTooltip
{
public string TooltipText => getParentMessage();
diff --git a/osu.Game/Overlays/Comments/GetCommentRepliesButton.cs b/osu.Game/Overlays/Comments/GetCommentRepliesButton.cs
new file mode 100644
index 0000000000..a3817ba416
--- /dev/null
+++ b/osu.Game/Overlays/Comments/GetCommentRepliesButton.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using System.Collections.Generic;
+using osuTK;
+
+namespace osu.Game.Overlays.Comments
+{
+ public abstract class GetCommentRepliesButton : LoadingButton
+ {
+ private const int duration = 200;
+
+ protected override IEnumerable EffectTargets => new[] { text };
+
+ private OsuSpriteText text;
+
+ protected GetCommentRepliesButton()
+ {
+ AutoSizeAxes = Axes.Both;
+ LoadingAnimationSize = new Vector2(8);
+ }
+
+ protected override Drawable CreateContent() => new Container
+ {
+ AutoSizeAxes = Axes.Both,
+ Child = text = new OsuSpriteText
+ {
+ AlwaysPresent = true,
+ Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
+ Text = GetText()
+ }
+ };
+
+ protected abstract string GetText();
+
+ protected override void OnLoadStarted() => text.FadeOut(duration, Easing.OutQuint);
+
+ protected override void OnLoadFinished() => text.FadeIn(duration, Easing.OutQuint);
+ }
+}
diff --git a/osu.Game/Overlays/Comments/ShowChildrenButton.cs b/osu.Game/Overlays/Comments/ShowChildrenButton.cs
index be04b6e5de..5ec7c1d471 100644
--- a/osu.Game/Overlays/Comments/ShowChildrenButton.cs
+++ b/osu.Game/Overlays/Comments/ShowChildrenButton.cs
@@ -3,8 +3,9 @@
using osu.Framework.Graphics;
using osu.Game.Graphics.Containers;
-using osu.Framework.Input.Events;
using osu.Framework.Bindables;
+using osuTK.Graphics;
+using osu.Game.Graphics;
namespace osu.Game.Overlays.Comments
{
@@ -15,20 +16,18 @@ namespace osu.Game.Overlays.Comments
protected ShowChildrenButton()
{
AutoSizeAxes = Axes.Both;
+ IdleColour = OsuColour.Gray(0.7f);
+ HoverColour = Color4.White;
}
protected override void LoadComplete()
{
+ Action = Expanded.Toggle;
+
Expanded.BindValueChanged(OnExpandedChanged, true);
base.LoadComplete();
}
protected abstract void OnExpandedChanged(ValueChangedEvent expanded);
-
- protected override bool OnClick(ClickEvent e)
- {
- Expanded.Value = !Expanded.Value;
- return true;
- }
}
}
diff --git a/osu.Game/Overlays/Comments/VotePill.cs b/osu.Game/Overlays/Comments/VotePill.cs
index 978846549e..aa9723ea85 100644
--- a/osu.Game/Overlays/Comments/VotePill.cs
+++ b/osu.Game/Overlays/Comments/VotePill.cs
@@ -33,6 +33,9 @@ namespace osu.Game.Overlays.Comments
[Resolved]
private IAPIProvider api { get; set; }
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
private readonly Comment comment;
private Box background;
private Box hoverLayer;
@@ -68,7 +71,7 @@ namespace osu.Game.Overlays.Comments
base.LoadComplete();
isVoted.Value = comment.IsVoted;
votesCount.Value = comment.VotesCount;
- isVoted.BindValueChanged(voted => background.Colour = voted.NewValue ? AccentColour : OsuColour.Gray(0.05f), true);
+ isVoted.BindValueChanged(voted => background.Colour = voted.NewValue ? AccentColour : colourProvider.Background6, true);
votesCount.BindValueChanged(count => votesCounter.Text = $"+{count.NewValue}", true);
}
diff --git a/osu.Game/Overlays/Direct/PlayButton.cs b/osu.Game/Overlays/Direct/PlayButton.cs
index 10abe15177..d9f335b6a7 100644
--- a/osu.Game/Overlays/Direct/PlayButton.cs
+++ b/osu.Game/Overlays/Direct/PlayButton.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Direct
private Color4 hoverColour;
private readonly SpriteIcon icon;
- private readonly LoadingAnimation loadingAnimation;
+ private readonly LoadingSpinner loadingSpinner;
private const float transition_duration = 500;
@@ -53,12 +53,12 @@ namespace osu.Game.Overlays.Direct
if (value)
{
icon.FadeTo(0.5f, transition_duration, Easing.OutQuint);
- loadingAnimation.Show();
+ loadingSpinner.Show();
}
else
{
icon.FadeTo(1, transition_duration, Easing.OutQuint);
- loadingAnimation.Hide();
+ loadingSpinner.Hide();
}
}
}
@@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Direct
RelativeSizeAxes = Axes.Both,
Icon = FontAwesome.Solid.Play,
},
- loadingAnimation = new LoadingAnimation
+ loadingSpinner = new LoadingSpinner
{
Size = new Vector2(15),
},
diff --git a/osu.Game/Overlays/Home/Friends/UserListToolbar.cs b/osu.Game/Overlays/Home/Friends/UserListToolbar.cs
new file mode 100644
index 0000000000..f7c5e9f4fd
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/UserListToolbar.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+using osu.Framework.Bindables;
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class UserListToolbar : CompositeDrawable
+ {
+ public Bindable SortCriteria => sortControl.Current;
+
+ public Bindable DisplayStyle => styleControl.Current;
+
+ private readonly UserSortTabControl sortControl;
+ private readonly OverlayPanelDisplayStyleControl styleControl;
+
+ public UserListToolbar()
+ {
+ AutoSizeAxes = Axes.Both;
+
+ AddInternal(new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(10, 0),
+ Children = new Drawable[]
+ {
+ sortControl = new UserSortTabControl
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ styleControl = new OverlayPanelDisplayStyleControl
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs b/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
new file mode 100644
index 0000000000..2479fa4638
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/UserSortTabControl.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.ComponentModel;
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class UserSortTabControl : OverlaySortTabControl
+ {
+ }
+
+ public enum UserSortCriteria
+ {
+ [Description(@"Recently Active")]
+ LastVisit,
+ Rank,
+ Username
+ }
+}
diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
new file mode 100644
index 0000000000..7269007b41
--- /dev/null
+++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
@@ -0,0 +1,101 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+using osu.Framework.Input.Events;
+using osu.Game.Graphics.UserInterface;
+using osu.Framework.Allocation;
+using osuTK.Graphics;
+using osu.Framework.Graphics.Cursor;
+
+namespace osu.Game.Overlays
+{
+ public class OverlayPanelDisplayStyleControl : OsuTabControl
+ {
+ protected override Dropdown CreateDropdown() => null;
+
+ protected override TabItem CreateTabItem(OverlayPanelDisplayStyle value) => new PanelDisplayTabItem(value);
+
+ protected override bool AddEnumEntriesAutomatically => false;
+
+ public OverlayPanelDisplayStyleControl()
+ {
+ AutoSizeAxes = Axes.Both;
+
+ AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Card)
+ {
+ Icon = FontAwesome.Solid.Square
+ });
+ AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.List)
+ {
+ Icon = FontAwesome.Solid.Bars
+ });
+ }
+
+ protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal
+ };
+
+ private class PanelDisplayTabItem : TabItem, IHasTooltip
+ {
+ public IconUsage Icon
+ {
+ set => icon.Icon = value;
+ }
+
+ [Resolved]
+ private OverlayColourProvider colourProvider { get; set; }
+
+ public string TooltipText => $@"{Value} view";
+
+ private readonly SpriteIcon icon;
+
+ public PanelDisplayTabItem(OverlayPanelDisplayStyle value)
+ : base(value)
+ {
+ Size = new Vector2(11);
+ AddRange(new Drawable[]
+ {
+ icon = new SpriteIcon
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ FillMode = FillMode.Fit
+ },
+ new HoverClickSounds()
+ });
+ }
+
+ protected override void OnActivated() => updateState();
+
+ protected override void OnDeactivated() => updateState();
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ updateState();
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ updateState();
+ base.OnHoverLost(e);
+ }
+
+ private void updateState() => icon.Colour = Active.Value || IsHovered ? colourProvider.Light1 : Color4.White;
+ }
+ }
+
+ public enum OverlayPanelDisplayStyle
+ {
+ Card,
+ List
+ }
+}
diff --git a/osu.Game/Overlays/OverlaySortTabControl.cs b/osu.Game/Overlays/OverlaySortTabControl.cs
index 5a713ab08e..395f3aec4c 100644
--- a/osu.Game/Overlays/OverlaySortTabControl.cs
+++ b/osu.Game/Overlays/OverlaySortTabControl.cs
@@ -15,6 +15,8 @@ using osu.Game.Graphics.Sprites;
using osuTK.Graphics;
using osu.Game.Overlays.Comments;
using JetBrains.Annotations;
+using System;
+using osu.Framework.Extensions;
namespace osu.Game.Overlays
{
@@ -132,7 +134,7 @@ namespace osu.Game.Overlays
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 12),
- Text = value.ToString()
+ Text = (value as Enum)?.GetDescription() ?? value.ToString()
}
}
});
diff --git a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs
index a89360bd3c..99325aa1da 100644
--- a/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs
+++ b/osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs
@@ -27,6 +27,8 @@ namespace osu.Game.Overlays.Rankings
protected override Drawable CreateContent() => countryFilter = new CountryFilter();
+ protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/rankings");
+
private class RankingsTitle : ScreenTitle
{
public readonly Bindable Scope = new Bindable();
diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
index e609fa1487..6f06eecd6e 100644
--- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
+++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
@@ -37,7 +37,7 @@ namespace osu.Game.Overlays.Rankings
private SpotlightSelector selector;
private Container content;
- private DimmedLoadingLayer loading;
+ private LoadingLayer loading;
[BackgroundDependencyLoader]
private void load()
@@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Rankings
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Vertical = 10 }
},
- loading = new DimmedLoadingLayer()
+ loading = new LoadingLayer(content)
}
}
}
diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs
index 2c5ea61315..afb23883ac 100644
--- a/osu.Game/Overlays/RankingsOverlay.cs
+++ b/osu.Game/Overlays/RankingsOverlay.cs
@@ -9,9 +9,9 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Overlays.Rankings;
using osu.Game.Users;
using osu.Game.Rulesets;
-using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using System.Threading;
+using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays.Rankings.Tables;
@@ -23,11 +23,9 @@ namespace osu.Game.Overlays
protected Bindable Scope => header.Current;
- private Bindable ruleset => header.Ruleset;
-
private readonly BasicScrollContainer scrollFlow;
private readonly Container contentContainer;
- private readonly DimmedLoadingLayer loading;
+ private readonly LoadingLayer loading;
private readonly Box background;
private readonly RankingsOverlayHeader header;
@@ -77,7 +75,7 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Bottom = 10 }
},
- loading = new DimmedLoadingLayer(),
+ loading = new LoadingLayer(contentContainer),
}
}
}
@@ -92,10 +90,15 @@ namespace osu.Game.Overlays
background.Colour = ColourProvider.Background5;
}
+ [Resolved]
+ private Bindable ruleset { get; set; }
+
protected override void LoadComplete()
{
base.LoadComplete();
+ header.Ruleset.BindTo(ruleset);
+
Country.BindValueChanged(_ =>
{
// if a country is requested, force performance scope.
@@ -121,6 +124,8 @@ namespace osu.Game.Overlays
Scheduler.AddOnce(loadNewContent);
});
+
+ Scheduler.AddOnce(loadNewContent);
}
public void ShowCountry(Country requested)
@@ -133,6 +138,12 @@ namespace osu.Game.Overlays
Country.Value = requested;
}
+ public void ShowSpotlights()
+ {
+ Scope.Value = RankingsScope.Spotlights;
+ Show();
+ }
+
private void loadNewContent()
{
loading.Show();
diff --git a/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs b/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs
index 0783c64c20..d6174e0733 100644
--- a/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs
+++ b/osu.Game/Overlays/SearchableList/SearchableListOverlay.cs
@@ -80,7 +80,7 @@ namespace osu.Game.Overlays.SearchableList
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Horizontal = WIDTH_PADDING, Bottom = 50 },
+ Padding = new MarginPadding { Horizontal = 10, Bottom = 50 },
Direction = FillDirection.Vertical,
},
},
diff --git a/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs
index 457f064f89..9edb18e065 100644
--- a/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs
@@ -22,11 +22,6 @@ namespace osu.Game.Overlays.Settings.Sections.Debug
Bindable = frameworkConfig.GetBindable(FrameworkSetting.ShowLogOverlay)
},
new SettingsCheckbox
- {
- LabelText = "Performance logging",
- Bindable = config.GetBindable(DebugSetting.PerformanceLogging)
- },
- new SettingsCheckbox
{
LabelText = "Bypass front-to-back render pass",
Bindable = config.GetBindable(DebugSetting.BypassFrontToBackPass)
diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
index c55183772b..bf0e073350 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
@@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
Children = new Drawable[]
{
- new LoadingAnimation
+ new LoadingSpinner
{
State = { Value = Visibility.Visible },
Anchor = Anchor.TopCentre,
diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs
index 7317076c54..69ff9b43e5 100644
--- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs
@@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
+using osu.Framework.Platform;
using osu.Game.Configuration;
namespace osu.Game.Overlays.Settings.Sections.Graphics
@@ -24,6 +25,11 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics
LabelText = "Frame limiter",
Bindable = config.GetBindable(FrameworkSetting.FrameSync)
},
+ new SettingsEnumDropdown
+ {
+ LabelText = "Threading mode",
+ Bindable = config.GetBindable(FrameworkSetting.ExecutionMode)
+ },
new SettingsCheckbox
{
LabelText = "Show FPS",
diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs
index 9a523bc1bc..54c978738d 100644
--- a/osu.Game/Overlays/SocialOverlay.cs
+++ b/osu.Game/Overlays/SocialOverlay.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Overlays
{
public class SocialOverlay : SearchableListOverlay
{
- private readonly LoadingAnimation loading;
+ private readonly LoadingSpinner loading;
private FillFlowContainer panels;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b");
@@ -54,7 +54,7 @@ namespace osu.Game.Overlays
public SocialOverlay()
: base(OverlayColourScheme.Pink)
{
- Add(loading = new LoadingAnimation());
+ Add(loading = new LoadingSpinner());
Filter.Search.Current.ValueChanged += text =>
{
diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs
index b044bc4de0..897587d198 100644
--- a/osu.Game/Overlays/Toolbar/Toolbar.cs
+++ b/osu.Game/Overlays/Toolbar/Toolbar.cs
@@ -70,6 +70,7 @@ namespace osu.Game.Overlays.Toolbar
Children = new Drawable[]
{
new ToolbarChangelogButton(),
+ new ToolbarRankingsButton(),
new ToolbarDirectButton(),
new ToolbarChatButton(),
new ToolbarSocialButton(),
diff --git a/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs
new file mode 100644
index 0000000000..cbd097696d
--- /dev/null
+++ b/osu.Game/Overlays/Toolbar/ToolbarRankingsButton.cs
@@ -0,0 +1,22 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics.Sprites;
+
+namespace osu.Game.Overlays.Toolbar
+{
+ public class ToolbarRankingsButton : ToolbarOverlayToggleButton
+ {
+ public ToolbarRankingsButton()
+ {
+ SetIcon(FontAwesome.Regular.ChartBar);
+ }
+
+ [BackgroundDependencyLoader(true)]
+ private void load(RankingsOverlay rankings)
+ {
+ StateContainer = rankings;
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
index 76fad945cc..4bff8146b4 100644
--- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
+++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
@@ -14,8 +14,25 @@ namespace osu.Game.Overlays.Volume
public Func ActionRequested;
public Func ScrollActionRequested;
- public bool OnPressed(GlobalAction action) => ActionRequested?.Invoke(action) ?? false;
- public bool OnScroll(GlobalAction action, float amount, bool isPrecise) => ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;
+ public bool OnPressed(GlobalAction action)
+ {
+ // if nothing else handles selection actions in the game, it's safe to let volume be adjusted.
+ switch (action)
+ {
+ case GlobalAction.SelectPrevious:
+ action = GlobalAction.IncreaseVolume;
+ break;
+
+ case GlobalAction.SelectNext:
+ action = GlobalAction.DecreaseVolume;
+ break;
+ }
+
+ return ActionRequested?.Invoke(action) ?? false;
+ }
+
+ public bool OnScroll(GlobalAction action, float amount, bool isPrecise) =>
+ ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;
public void OnReleased(GlobalAction action)
{
diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs
index 7effd290e6..07accf8820 100644
--- a/osu.Game/Overlays/Volume/VolumeMeter.cs
+++ b/osu.Game/Overlays/Volume/VolumeMeter.cs
@@ -11,16 +11,18 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
+using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
+using osu.Game.Input.Bindings;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Volume
{
- public class VolumeMeter : Container
+ public class VolumeMeter : Container, IKeyBindingHandler
{
private CircularProgress volumeCircle;
private CircularProgress volumeCircleGlow;
@@ -260,5 +262,28 @@ namespace osu.Game.Overlays.Volume
{
this.ScaleTo(1f, transition_length, Easing.OutExpo);
}
+
+ public bool OnPressed(GlobalAction action)
+ {
+ if (!IsHovered)
+ return false;
+
+ switch (action)
+ {
+ case GlobalAction.SelectPrevious:
+ adjust(1, false);
+ return true;
+
+ case GlobalAction.SelectNext:
+ adjust(-1, false);
+ return true;
+ }
+
+ return false;
+ }
+
+ public void OnReleased(GlobalAction action)
+ {
+ }
}
}
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs b/osu.Game/Rulesets/Judgements/IgnoreJudgement.cs
similarity index 63%
rename from osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs
rename to osu.Game/Rulesets/Judgements/IgnoreJudgement.cs
index b28b6a0d17..1871249c94 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellTickJudgement.cs
+++ b/osu.Game/Rulesets/Judgements/IgnoreJudgement.cs
@@ -1,11 +1,11 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Scoring;
-namespace osu.Game.Rulesets.Taiko.Judgements
+namespace osu.Game.Rulesets.Judgements
{
- public class TaikoSwellTickJudgement : TaikoJudgement
+ public class IgnoreJudgement : Judgement
{
public override bool AffectsCombo => false;
diff --git a/osu.Game/Rulesets/Judgements/Judgement.cs b/osu.Game/Rulesets/Judgements/Judgement.cs
index 599135ba54..9105b920ca 100644
--- a/osu.Game/Rulesets/Judgements/Judgement.cs
+++ b/osu.Game/Rulesets/Judgements/Judgement.cs
@@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Judgements
return -DEFAULT_MAX_HEALTH_INCREASE * 0.01;
case HitResult.Good:
- return DEFAULT_MAX_HEALTH_INCREASE * 0.3;
+ return DEFAULT_MAX_HEALTH_INCREASE * 0.5;
case HitResult.Great:
return DEFAULT_MAX_HEALTH_INCREASE;
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index 67fe18e8dd..aa29e42fac 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -99,12 +99,9 @@ namespace osu.Game.Rulesets.Objects.Drawables
{
var judgement = HitObject.CreateJudgement();
- if (judgement != null)
- {
- Result = CreateResult(judgement);
- if (Result == null)
- throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
- }
+ Result = CreateResult(judgement);
+ if (Result == null)
+ throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
loadSamples();
}
@@ -224,18 +221,6 @@ namespace osu.Game.Rulesets.Objects.Drawables
///
public event Action ApplyCustomUpdateState;
-#pragma warning disable 618 // (legacy state management) - can be removed 20200227
-
- ///
- /// Enables automatic transform management of this hitobject. Implementation of transforms should be done in and only. Rewinding and removing previous states is done automatically.
- ///
- ///
- /// Going forward, this is the preferred way of implementing s. Previous functionality
- /// is offered as a compatibility layer until all rulesets have been migrated across.
- ///
- [Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227
- protected virtual bool UseTransformStateManagement => true;
-
protected override void ClearInternal(bool disposeChildren = true) => throw new InvalidOperationException($"Should never clear a {nameof(DrawableHitObject)}");
private void updateState(ArmedState newState, bool force = false)
@@ -243,35 +228,28 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (State.Value == newState && !force)
return;
- if (UseTransformStateManagement)
+ LifetimeEnd = double.MaxValue;
+
+ double transformTime = HitObject.StartTime - InitialLifetimeOffset;
+
+ base.ApplyTransformsAt(double.MinValue, true);
+ base.ClearTransformsAfter(double.MinValue, true);
+
+ using (BeginAbsoluteSequence(transformTime, true))
{
- LifetimeEnd = double.MaxValue;
+ UpdateInitialTransforms();
- double transformTime = HitObject.StartTime - InitialLifetimeOffset;
+ var judgementOffset = Result?.TimeOffset ?? 0;
- base.ApplyTransformsAt(double.MinValue, true);
- base.ClearTransformsAfter(double.MinValue, true);
-
- using (BeginAbsoluteSequence(transformTime, true))
+ using (BeginDelayedSequence(InitialLifetimeOffset + judgementOffset, true))
{
- UpdateInitialTransforms();
-
- var judgementOffset = Result?.TimeOffset ?? 0;
-
- using (BeginDelayedSequence(InitialLifetimeOffset + judgementOffset, true))
- {
- UpdateStateTransforms(newState);
- state.Value = newState;
- }
+ UpdateStateTransforms(newState);
+ state.Value = newState;
}
-
- if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue)
- Expire();
}
- else
- state.Value = newState;
- UpdateState(newState);
+ if (state.Value != ArmedState.Idle && LifetimeEnd == double.MaxValue || HitObject.HitWindows == null)
+ Expire();
// apply any custom state overrides
ApplyCustomUpdateState?.Invoke(this, newState);
@@ -306,30 +284,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null)
{
- // When we are using automatic state management, parent calls to this should be blocked for safety.
- if (!UseTransformStateManagement)
- base.ClearTransformsAfter(time, propagateChildren, targetMember);
+ // Parent calls to this should be blocked for safety, as we are manually handling this in updateState.
}
public override void ApplyTransformsAt(double time, bool propagateChildren = false)
{
- // When we are using automatic state management, parent calls to this should be blocked for safety.
- if (!UseTransformStateManagement)
- base.ApplyTransformsAt(time, propagateChildren);
+ // Parent calls to this should be blocked for safety, as we are manually handling this in updateState.
}
- ///
- /// Legacy method to handle state changes.
- /// Should generally not be used when is true; use instead.
- ///
- /// The new armed state.
- [Obsolete("Use UpdateInitialTransforms()/UpdateStateTransforms() instead")] // can be removed 20200227
- protected virtual void UpdateState(ArmedState state)
- {
- }
-
-#pragma warning restore 618
-
#endregion
protected sealed override void SkinChanged(ISkinSource skin, bool allowFallback)
diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs
index c09844e0c6..9a8efdde84 100644
--- a/osu.Game/Rulesets/Objects/HitObject.cs
+++ b/osu.Game/Rulesets/Objects/HitObject.cs
@@ -144,9 +144,9 @@ namespace osu.Game.Rulesets.Objects
///
/// Creates the that represents the scoring information for this .
- /// May be null.
///
- public virtual Judgement CreateJudgement() => null;
+ [NotNull]
+ public virtual Judgement CreateJudgement() => new Judgement();
///
/// Creates the for this .
diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs
index febfd3696c..19722fb796 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertHit.cs
@@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
///
/// Legacy osu!catch Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject, IHasCombo, IHasXPosition
+ internal sealed class ConvertHit : ConvertHitObject, IHasCombo, IHasXPosition
{
public float X { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs
index 0089d1eb88..9de311c9d7 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Catch/ConvertSpinner.cs
@@ -8,7 +8,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
///
/// Legacy osu!catch Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition, IHasCombo
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition, IHasCombo
{
public double EndTime { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs
new file mode 100644
index 0000000000..e3b0d8a498
--- /dev/null
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObject.cs
@@ -0,0 +1,18 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Scoring;
+
+namespace osu.Game.Rulesets.Objects.Legacy
+{
+ ///
+ /// A hit object only used for conversion, not actual gameplay.
+ ///
+ internal abstract class ConvertHitObject : HitObject
+ {
+ public override Judgement CreateJudgement() => new IgnoreJudgement();
+
+ protected override HitWindows CreateHitWindows() => HitWindows.Empty;
+ }
+}
diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
index 53cdf457c4..924182b265 100644
--- a/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/ConvertSlider.cs
@@ -9,7 +9,7 @@ using osu.Game.Beatmaps.ControlPoints;
namespace osu.Game.Rulesets.Objects.Legacy
{
- internal abstract class ConvertSlider : HitObject, IHasCurve, IHasLegacyLastTickOffset
+ internal abstract class ConvertSlider : ConvertHitObject, IHasCurve, IHasLegacyLastTickOffset
{
///
/// Scoring distance with a speed-adjusted beat length of 1 second.
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
index 883ef55df0..0b69817c13 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHit.cs
@@ -2,17 +2,14 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
///
/// Legacy osu!mania Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject, IHasXPosition
+ internal sealed class ConvertHit : ConvertHitObject, IHasXPosition
{
public float X { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
index 69e6f8379d..1d92d638dd 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertHold.cs
@@ -2,18 +2,15 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
- internal sealed class ConvertHold : HitObject, IHasXPosition, IHasEndTime
+ internal sealed class ConvertHold : ConvertHitObject, IHasXPosition, IHasEndTime
{
public float X { get; set; }
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
index 4486c5d906..84cde5fa95 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSlider.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
@@ -12,7 +11,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
internal sealed class ConvertSlider : Legacy.ConvertSlider, IHasXPosition
{
public float X { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
index c6d1f1922c..7dc13e27cd 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Mania/ConvertSpinner.cs
@@ -2,21 +2,18 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Mania
{
///
/// Legacy osu!mania Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasXPosition
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasXPosition
{
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
public float X { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
index e40b5b4505..069366bad3 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertHit.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Objects.Legacy.Osu
@@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
///
/// Legacy osu! Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject, IHasPosition, IHasCombo
+ internal sealed class ConvertHit : ConvertHitObject, IHasPosition, IHasCombo
{
public Vector2 Position { get; set; }
@@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public bool NewCombo { get; set; }
public int ComboOffset { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
index a163329d47..e947690668 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSlider.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Objects.Legacy.Osu
@@ -21,7 +20,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public bool NewCombo { get; set; }
public int ComboOffset { get; set; }
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
index 5d96a61633..8b21aab411 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Osu/ConvertSpinner.cs
@@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
using osuTK;
namespace osu.Game.Rulesets.Objects.Legacy.Osu
@@ -10,7 +9,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
///
/// Legacy osu! Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime, IHasPosition, IHasCombo
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime, IHasPosition, IHasCombo
{
public double EndTime { get; set; }
@@ -22,8 +21,6 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
public float Y => Position.Y;
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
-
public bool NewCombo { get; set; }
public int ComboOffset { get; set; }
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
index efb9810927..cb5178ce48 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertHit.cs
@@ -1,15 +1,12 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Rulesets.Scoring;
-
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
///
/// Legacy osu!taiko Hit-type, used for parsing Beatmaps.
///
- internal sealed class ConvertHit : HitObject
+ internal sealed class ConvertHit : ConvertHitObject
{
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
index b365fd34ae..821554f7ee 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSlider.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Rulesets.Scoring;
-
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
///
@@ -10,6 +8,5 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
///
internal sealed class ConvertSlider : Legacy.ConvertSlider
{
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
index 840ba51ac2..8e28487f2f 100644
--- a/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
+++ b/osu.Game/Rulesets/Objects/Legacy/Taiko/ConvertSpinner.cs
@@ -2,19 +2,16 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Objects.Types;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Objects.Legacy.Taiko
{
///
/// Legacy osu!taiko Spinner-type, used for parsing Beatmaps.
///
- internal sealed class ConvertSpinner : HitObject, IHasEndTime
+ internal sealed class ConvertSpinner : ConvertHitObject, IHasEndTime
{
public double EndTime { get; set; }
public double Duration => EndTime - StartTime;
-
- protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}
}
diff --git a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs
index 3016007f98..334b95f808 100644
--- a/osu.Game/Rulesets/Scoring/JudgementProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/JudgementProcessor.cs
@@ -125,8 +125,6 @@ namespace osu.Game.Rulesets.Scoring
simulate(nested);
var judgement = obj.CreateJudgement();
- if (judgement == null)
- return;
var result = CreateResult(obj, judgement);
if (result == null)
diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs
index 83a7f7289f..108f98d5fc 100644
--- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs
+++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs
@@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Caching;
using osu.Framework.Graphics;
+using osu.Framework.Layout;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Types;
@@ -19,11 +20,13 @@ namespace osu.Game.Rulesets.UI.Scrolling
[Resolved]
private IScrollingInfo scrollingInfo { get; set; }
- private readonly Cached initialStateCache = new Cached();
+ private readonly LayoutValue initialStateCache = new LayoutValue(Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo);
public ScrollingHitObjectContainer()
{
RelativeSizeAxes = Axes.Both;
+
+ AddLayout(initialStateCache);
}
[BackgroundDependencyLoader]
@@ -55,14 +58,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
return result;
}
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & (Invalidation.RequiredParentSizeToFit | Invalidation.DrawInfo)) > 0)
- initialStateCache.Invalidate();
-
- return base.Invalidate(invalidation, source, shallPropagate);
- }
-
private float scrollLength;
protected override void Update()
diff --git a/osu.Game/Screens/Charts/ChartInfo.cs b/osu.Game/Screens/Charts/ChartInfo.cs
deleted file mode 100644
index d9a9ad5eeb..0000000000
--- a/osu.Game/Screens/Charts/ChartInfo.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-namespace osu.Game.Screens.Charts
-{
- public class ChartInfo : ScreenWhiteBox
- {
- }
-}
diff --git a/osu.Game/Screens/Charts/ChartListing.cs b/osu.Game/Screens/Charts/ChartListing.cs
deleted file mode 100644
index 18bba6433f..0000000000
--- a/osu.Game/Screens/Charts/ChartListing.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-
-namespace osu.Game.Screens.Charts
-{
- public class ChartListing : ScreenWhiteBox
- {
- protected override IEnumerable PossibleChildren => new[]
- {
- typeof(ChartInfo)
- };
- }
-}
diff --git a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
index 479de64eab..3a42938fc1 100644
--- a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
@@ -3,10 +3,10 @@
using System;
using osu.Framework.Allocation;
-using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
+using osu.Framework.Layout;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osuTK;
@@ -51,7 +51,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
[Resolved]
private BindableBeatDivisor beatDivisor { get; set; }
- private readonly Cached gridCache = new Cached();
+ private readonly LayoutValue gridCache = new LayoutValue(Invalidation.RequiredParentSizeToFit);
private readonly double? endTime;
///
@@ -67,6 +67,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
StartTime = startTime;
RelativeSizeAxes = Axes.Both;
+
+ AddLayout(gridCache);
}
protected override void LoadComplete()
@@ -92,14 +94,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
gridCache.Invalidate();
}
- public override bool Invalidate(Invalidation invalidation = Invalidation.All, Drawable source = null, bool shallPropagate = true)
- {
- if ((invalidation & Invalidation.RequiredParentSizeToFit) > 0)
- gridCache.Invalidate();
-
- return base.Invalidate(invalidation, source, shallPropagate);
- }
-
protected override void Update()
{
base.Update();
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 3bec4b8f6f..3a6f02f811 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -93,15 +93,15 @@ namespace osu.Game.Screens.Edit
EditorMenuBar menuBar;
- var fileMenuItems = new List
-
- true
-
Static
@@ -73,8 +70,8 @@
-
-
+
+
@@ -82,7 +79,7 @@
-
+
diff --git a/osu.iOS/OsuGameIOS.cs b/osu.iOS/OsuGameIOS.cs
index e5ff4aec95..3a16f81530 100644
--- a/osu.iOS/OsuGameIOS.cs
+++ b/osu.iOS/OsuGameIOS.cs
@@ -11,12 +11,5 @@ namespace osu.iOS
public class OsuGameIOS : OsuGame
{
public override Version AssemblyVersion => new Version(NSBundle.MainBundle.InfoDictionary["CFBundleVersion"].ToString());
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
-
- Add(new UpdateManager());
- }
}
}
diff --git a/osu.iOS/osu.iOS.csproj b/osu.iOS/osu.iOS.csproj
index d60a3475e7..1e9a21865d 100644
--- a/osu.iOS/osu.iOS.csproj
+++ b/osu.iOS/osu.iOS.csproj
@@ -7,6 +7,7 @@
{3F082D0B-A964-43D7-BDF7-C256D76A50D0}
osu.iOS
osu.iOS
+ false
@@ -116,4 +117,4 @@
-
\ No newline at end of file
+