1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 19:03:08 +08:00

Merge remote-tracking branch 'origin/master'

This commit is contained in:
smoogipoo 2019-08-26 17:37:06 +09:00
commit fd4c6e08ca
127 changed files with 999 additions and 475 deletions

View File

@ -6,7 +6,7 @@ GEM
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 4.0)
atomos (0.1.3) atomos (0.1.3)
babosa (1.0.2) babosa (1.0.2)
claide (1.0.2) claide (1.0.3)
colored (1.2) colored (1.2)
colored2 (3.1.2) colored2 (3.1.2)
commander-fastlane (4.4.6) commander-fastlane (4.4.6)
@ -14,11 +14,11 @@ GEM
declarative (0.0.10) declarative (0.0.10)
declarative-option (0.1.0) declarative-option (0.1.0)
digest-crc (0.4.1) digest-crc (0.4.1)
domain_name (0.5.20180417) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.1) dotenv (2.7.5)
emoji_regex (1.0.1) emoji_regex (1.0.1)
excon (0.62.0) excon (0.66.0)
faraday (0.15.4) faraday (0.15.4)
multipart-post (>= 1.2, < 3) multipart-post (>= 1.2, < 3)
faraday-cookie_jar (0.0.6) faraday-cookie_jar (0.0.6)
@ -27,7 +27,7 @@ GEM
faraday_middleware (0.13.1) faraday_middleware (0.13.1)
faraday (>= 0.7.4, < 1.0) faraday (>= 0.7.4, < 1.0)
fastimage (2.1.5) fastimage (2.1.5)
fastlane (2.117.0) fastlane (2.129.0)
CFPropertyList (>= 2.3, < 4.0.0) CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.3, < 3.0.0) addressable (>= 2.3, < 3.0.0)
babosa (>= 1.0.2, < 2.0.0) babosa (>= 1.0.2, < 2.0.0)
@ -46,8 +46,8 @@ GEM
google-cloud-storage (>= 1.15.0, < 2.0.0) google-cloud-storage (>= 1.15.0, < 2.0.0)
highline (>= 1.7.2, < 2.0.0) highline (>= 1.7.2, < 2.0.0)
json (< 3.0.0) json (< 3.0.0)
mini_magick (~> 4.5.1) jwt (~> 2.1.0)
multi_json mini_magick (>= 4.9.4, < 5.0.0)
multi_xml (~> 0.5) multi_xml (~> 0.5)
multipart-post (~> 2.0.0) multipart-post (~> 2.0.0)
plist (>= 3.1.0, < 4.0.0) plist (>= 3.1.0, < 4.0.0)
@ -56,15 +56,15 @@ GEM
security (= 0.1.3) security (= 0.1.3)
simctl (~> 1.6.3) simctl (~> 1.6.3)
slack-notifier (>= 2.0.0, < 3.0.0) slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 1.6.2, < 2.0.0) terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0) terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0) tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0) word_wrap (~> 1.0.0)
xcodeproj (>= 1.6.0, < 2.0.0) xcodeproj (>= 1.8.1, < 2.0.0)
xcpretty (~> 0.3.0) xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3) xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-clean_testflight_testers (0.2.0) fastlane-plugin-clean_testflight_testers (0.3.0)
fastlane-plugin-souyuz (0.8.1) fastlane-plugin-souyuz (0.8.1)
souyuz (>= 0.8.1) souyuz (>= 0.8.1)
fastlane-plugin-xamarin (0.6.3) fastlane-plugin-xamarin (0.6.3)
@ -79,7 +79,7 @@ GEM
signet (~> 0.9) signet (~> 0.9)
google-cloud-core (1.3.0) google-cloud-core (1.3.0)
google-cloud-env (~> 1.0) google-cloud-env (~> 1.0)
google-cloud-env (1.0.5) google-cloud-env (1.2.0)
faraday (~> 0.11) faraday (~> 0.11)
google-cloud-storage (1.16.0) google-cloud-storage (1.16.0)
digest-crc (~> 0.4) digest-crc (~> 0.4)
@ -102,17 +102,17 @@ GEM
memoist (0.16.0) memoist (0.16.0)
mime-types (3.2.2) mime-types (3.2.2)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2018.0812) mime-types-data (3.2019.0331)
mini_magick (4.5.1) mini_magick (4.9.5)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
multi_json (1.13.1) multi_json (1.13.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
nanaimo (0.2.6) nanaimo (0.2.6)
naturally (2.2.0) naturally (2.2.0)
nokogiri (1.10.1) nokogiri (1.10.4)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
os (1.0.0) os (1.0.1)
plist (3.5.0) plist (3.5.0)
public_suffix (2.0.5) public_suffix (2.0.5)
representable (3.0.4) representable (3.0.4)
@ -121,7 +121,7 @@ GEM
uber (< 0.2.0) uber (< 0.2.0)
retriable (3.1.2) retriable (3.1.2)
rouge (2.0.7) rouge (2.0.7)
rubyzip (1.2.2) rubyzip (1.2.3)
security (0.1.3) security (0.1.3)
signet (0.11.0) signet (0.11.0)
addressable (~> 2.3) addressable (~> 2.3)
@ -136,20 +136,20 @@ GEM
fastlane (>= 2.29.0) fastlane (>= 2.29.0)
highline (~> 1.7) highline (~> 1.7)
nokogiri (~> 1.7) nokogiri (~> 1.7)
terminal-notifier (1.8.0) terminal-notifier (2.0.0)
terminal-table (1.8.0) terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1) unicode-display_width (~> 1.1, >= 1.1.1)
tty-cursor (0.6.1) tty-cursor (0.7.0)
tty-screen (0.6.5) tty-screen (0.7.0)
tty-spinner (0.9.0) tty-spinner (0.9.1)
tty-cursor (~> 0.6.0) tty-cursor (~> 0.7)
uber (0.1.0) uber (0.1.0)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.5) unf_ext (0.0.7.6)
unicode-display_width (1.4.1) unicode-display_width (1.6.0)
word_wrap (1.0.0) word_wrap (1.0.0)
xcodeproj (1.8.1) xcodeproj (1.12.0)
CFPropertyList (>= 2.3.3, < 4.0) CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3) atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0) claide (>= 1.0.2, < 2.0)

View File

@ -1,22 +1,6 @@
update_fastlane update_fastlane
default_platform(:ios)
platform :ios do platform :ios do
lane :testflight_prune_dry do
clean_testflight_testers(days_of_inactivity:45, dry_run: true)
end
# Specify a custom number for what's "inactive"
lane :testflight_prune do
clean_testflight_testers(days_of_inactivity: 45) # 120 days, so about 4 months
end
lane :update_version do |options|
options[:plist_path] = '../osu.iOS/Info.plist'
app_version(options)
end
desc 'Deploy to testflight' desc 'Deploy to testflight'
lane :beta do |options| lane :beta do |options|
update_version(options) update_version(options)
@ -62,4 +46,17 @@ platform :ios do
match(options) match(options)
end end
lane :update_version do |options|
options[:plist_path] = '../osu.iOS/Info.plist'
app_version(options)
end
lane :testflight_prune_dry do
clean_testflight_testers(days_of_inactivity:45, dry_run: true)
end
lane :testflight_prune do
clean_testflight_testers(days_of_inactivity: 45)
end
end end

View File

@ -16,21 +16,6 @@ or alternatively using `brew cask install fastlane`
# Available Actions # Available Actions
## iOS ## iOS
### ios testflight_prune_dry
```
fastlane ios testflight_prune_dry
```
### ios testflight_prune
```
fastlane ios testflight_prune
```
### ios update_version
```
fastlane ios update_version
```
### ios beta ### ios beta
``` ```
fastlane ios beta fastlane ios beta
@ -46,6 +31,21 @@ Compile the project
fastlane ios provision fastlane ios provision
``` ```
Install provisioning profiles using match Install provisioning profiles using match
### ios update_version
```
fastlane ios update_version
```
### ios testflight_prune_dry
```
fastlane ios testflight_prune_dry
```
### ios testflight_prune
```
fastlane ios testflight_prune
```
---- ----

View File

@ -60,7 +60,7 @@
<Reference Include="Java.Interop" /> <Reference Include="Java.Interop" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.809.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.823.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.814.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2019.823.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -81,7 +81,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
AccentColour = Color4.Red, AccentColour = Color4.Red,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0.5f, Alpha = 0.5f,
Scale = new Vector2(1.333f) Scale = new Vector2(1.333f)
}); });

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Colour = Color4.White.Opacity(0.9f); Colour = Color4.White.Opacity(0.9f);
} }

View File

@ -201,7 +201,7 @@ namespace osu.Game.Rulesets.Catch.UI
additive.Scale = Scale; additive.Scale = Scale;
additive.Colour = HyperDashing ? Color4.Red : Color4.White; additive.Colour = HyperDashing ? Color4.Red : Color4.White;
additive.RelativePositionAxes = RelativePositionAxes; additive.RelativePositionAxes = RelativePositionAxes;
additive.Blending = BlendingMode.Additive; additive.Blending = BlendingParameters.Additive;
AdditiveTarget.Add(additive); AdditiveTarget.Add(additive);

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -26,14 +26,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
public BodyPiece() public BodyPiece()
{ {
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Children = new[] Children = new[]
{ {
Background = new Box { RelativeSizeAxes = Axes.Both }, Background = new Box { RelativeSizeAxes = Axes.Both },
Foreground = new BufferedContainer Foreground = new BufferedContainer
{ {
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
CacheDrawnFrameBuffer = true, CacheDrawnFrameBuffer = true,
Children = new Drawable[] Children = new Drawable[]

View File

@ -61,7 +61,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Name = "Top", Name = "Top",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.5f, Height = 0.5f,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha)) Colour = ColourInfo.GradientVertical(Color4.Transparent, Color4.White.Opacity(alpha))
}, },
new Box new Box
@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables.Pieces
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.5f, Height = 0.5f,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent) Colour = ColourInfo.GradientVertical(Color4.White.Opacity(alpha), Color4.Transparent)
} }
}; };

View File

@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
Name = "Background Gradient Overlay", Name = "Background Gradient Overlay",
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0.5f, Height = 0.5f,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0 Alpha = 0
} }
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -2,12 +2,12 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.IO; using System.Text.RegularExpressions;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Textures;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
@ -28,11 +28,11 @@ namespace osu.Game.Rulesets.Osu.Tests
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {
var skins = new SkinManager(LocalStorage, ContextFactory, null, audio); var dllStore = new DllResourceStore("osu.Game.Rulesets.Osu.Tests.dll");
metricsSkin = getSkinFromResources(skins, "metrics_skin"); metricsSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/metrics_skin"), audio, true);
defaultSkin = getSkinFromResources(skins, "default_skin"); defaultSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/default_skin"), audio, false);
specialSkin = getSkinFromResources(skins, "special_skin"); specialSkin = new TestLegacySkin(new SkinInfo(), new NamespacedResourceStore<byte[]>(dllStore, "Resources/special_skin"), audio, true);
} }
public void SetContents(Func<Drawable> creationFunction) public void SetContents(Func<Drawable> creationFunction)
@ -43,23 +43,28 @@ namespace osu.Game.Rulesets.Osu.Tests
Cell(3).Child = new LocalSkinOverrideContainer(specialSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction()); Cell(3).Child = new LocalSkinOverrideContainer(specialSkin) { RelativeSizeAxes = Axes.Both }.WithChild(creationFunction());
} }
private static Skin getSkinFromResources(SkinManager skins, string name) private class TestLegacySkin : LegacySkin
{ {
using (var storage = new DllResourceStore("osu.Game.Rulesets.Osu.Tests.dll")) private readonly bool extrapolateAnimations;
public TestLegacySkin(SkinInfo skin, IResourceStore<byte[]> storage, AudioManager audioManager, bool extrapolateAnimations)
: base(skin, storage, audioManager, "skin.ini")
{ {
var tempName = Path.GetTempFileName(); this.extrapolateAnimations = extrapolateAnimations;
}
File.Delete(tempName); public override Texture GetTexture(string componentName)
Directory.CreateDirectory(tempName); {
// extrapolate frames to test longer animations
if (extrapolateAnimations)
{
var match = Regex.Match(componentName, "-([0-9]*)");
var files = storage.GetAvailableResources().Where(f => f.StartsWith($"Resources/{name}")); if (match.Length > 0 && int.TryParse(match.Groups[1].Value, out var number) && number < 60)
return base.GetTexture(componentName.Replace($"-{number}", $"-{number % 2}"));
}
foreach (var file in files) return base.GetTexture(componentName);
using (var stream = storage.GetStream(file))
using (var newFile = File.Create(Path.Combine(tempName, Path.GetFileName(file))))
stream.CopyTo(newFile);
return skins.GetSkin(skins.Import(tempName).Result);
} }
} }
} }

View File

@ -0,0 +1,34 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneDrawableJudgement : SkinnableTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(DrawableJudgement),
typeof(DrawableOsuJudgement)
};
public TestSceneDrawableJudgement()
{
foreach (HitResult result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Skip(1))
AddStep("Show " + result.GetDescription(), () => SetContents(() =>
new DrawableOsuJudgement(new JudgementResult(null) { Type = result }, null)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
}));
}
}
}

View File

@ -10,7 +10,6 @@ using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Tests.Visual;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -27,83 +26,96 @@ using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
{ {
[TestFixture] [TestFixture]
public class TestSceneSlider : OsuTestScene public class TestSceneSlider : SkinnableTestScene
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(Slider),
typeof(SliderTick),
typeof(SliderTailCircle),
typeof(SliderBall), typeof(SliderBall),
typeof(SliderBody), typeof(SliderBody),
typeof(SliderTick), typeof(SnakingSliderBody),
typeof(DrawableSlider), typeof(DrawableSlider),
typeof(DrawableSliderTick), typeof(DrawableSliderTick),
typeof(DrawableSliderTail),
typeof(DrawableSliderHead),
typeof(DrawableRepeatPoint), typeof(DrawableRepeatPoint),
typeof(DrawableOsuHitObject) typeof(DrawableOsuHitObject)
}; };
private readonly Container content; private Container content;
protected override Container<Drawable> Content => content;
protected override Container<Drawable> Content
{
get
{
if (content == null)
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 }));
return content;
}
}
private int depthIndex; private int depthIndex;
public TestSceneSlider() public TestSceneSlider()
{ {
base.Content.Add(content = new OsuInputManager(new RulesetInfo { ID = 0 })); AddStep("Big Single", () => SetContents(() => testSimpleBig()));
AddStep("Medium Single", () => SetContents(() => testSimpleMedium()));
AddStep("Small Single", () => SetContents(() => testSimpleSmall()));
AddStep("Big 1 Repeat", () => SetContents(() => testSimpleBig(1)));
AddStep("Medium 1 Repeat", () => SetContents(() => testSimpleMedium(1)));
AddStep("Small 1 Repeat", () => SetContents(() => testSimpleSmall(1)));
AddStep("Big 2 Repeats", () => SetContents(() => testSimpleBig(2)));
AddStep("Medium 2 Repeats", () => SetContents(() => testSimpleMedium(2)));
AddStep("Small 2 Repeats", () => SetContents(() => testSimpleSmall(2)));
AddStep("Big Single", () => testSimpleBig()); AddStep("Slow Slider", () => SetContents(testSlowSpeed)); // slow long sliders take ages already so no repeat steps
AddStep("Medium Single", () => testSimpleMedium()); AddStep("Slow Short Slider", () => SetContents(() => testShortSlowSpeed()));
AddStep("Small Single", () => testSimpleSmall()); AddStep("Slow Short Slider 1 Repeats", () => SetContents(() => testShortSlowSpeed(1)));
AddStep("Big 1 Repeat", () => testSimpleBig(1)); AddStep("Slow Short Slider 2 Repeats", () => SetContents(() => testShortSlowSpeed(2)));
AddStep("Medium 1 Repeat", () => testSimpleMedium(1));
AddStep("Small 1 Repeat", () => testSimpleSmall(1));
AddStep("Big 2 Repeats", () => testSimpleBig(2));
AddStep("Medium 2 Repeats", () => testSimpleMedium(2));
AddStep("Small 2 Repeats", () => testSimpleSmall(2));
AddStep("Slow Slider", testSlowSpeed); // slow long sliders take ages already so no repeat steps AddStep("Fast Slider", () => SetContents(() => testHighSpeed()));
AddStep("Slow Short Slider", () => testShortSlowSpeed()); AddStep("Fast Slider 1 Repeat", () => SetContents(() => testHighSpeed(1)));
AddStep("Slow Short Slider 1 Repeats", () => testShortSlowSpeed(1)); AddStep("Fast Slider 2 Repeats", () => SetContents(() => testHighSpeed(2)));
AddStep("Slow Short Slider 2 Repeats", () => testShortSlowSpeed(2)); AddStep("Fast Short Slider", () => SetContents(() => testShortHighSpeed()));
AddStep("Fast Short Slider 1 Repeat", () => SetContents(() => testShortHighSpeed(1)));
AddStep("Fast Short Slider 2 Repeats", () => SetContents(() => testShortHighSpeed(2)));
AddStep("Fast Short Slider 6 Repeats", () => SetContents(() => testShortHighSpeed(6)));
AddStep("Fast Slider", () => testHighSpeed()); AddStep("Perfect Curve", () => SetContents(() => testPerfect()));
AddStep("Fast Slider 1 Repeat", () => testHighSpeed(1)); AddStep("Perfect Curve 1 Repeat", () => SetContents(() => testPerfect(1)));
AddStep("Fast Slider 2 Repeats", () => testHighSpeed(2)); AddStep("Perfect Curve 2 Repeats", () => SetContents(() => testPerfect(2)));
AddStep("Fast Short Slider", () => testShortHighSpeed());
AddStep("Fast Short Slider 1 Repeat", () => testShortHighSpeed(1));
AddStep("Fast Short Slider 2 Repeats", () => testShortHighSpeed(2));
AddStep("Fast Short Slider 6 Repeats", () => testShortHighSpeed(6));
AddStep("Perfect Curve", () => testPerfect()); AddStep("Linear Slider", () => SetContents(() => testLinear()));
AddStep("Perfect Curve 1 Repeat", () => testPerfect(1)); AddStep("Linear Slider 1 Repeat", () => SetContents(() => testLinear(1)));
AddStep("Perfect Curve 2 Repeats", () => testPerfect(2)); AddStep("Linear Slider 2 Repeats", () => SetContents(() => testLinear(2)));
AddStep("Linear Slider", () => testLinear()); AddStep("Bezier Slider", () => SetContents(() => testBezier()));
AddStep("Linear Slider 1 Repeat", () => testLinear(1)); AddStep("Bezier Slider 1 Repeat", () => SetContents(() => testBezier(1)));
AddStep("Linear Slider 2 Repeats", () => testLinear(2)); AddStep("Bezier Slider 2 Repeats", () => SetContents(() => testBezier(2)));
AddStep("Bezier Slider", () => testBezier()); AddStep("Linear Overlapping", () => SetContents(() => testLinearOverlapping()));
AddStep("Bezier Slider 1 Repeat", () => testBezier(1)); AddStep("Linear Overlapping 1 Repeat", () => SetContents(() => testLinearOverlapping(1)));
AddStep("Bezier Slider 2 Repeats", () => testBezier(2)); AddStep("Linear Overlapping 2 Repeats", () => SetContents(() => testLinearOverlapping(2)));
AddStep("Linear Overlapping", () => testLinearOverlapping()); AddStep("Catmull Slider", () => SetContents(() => testCatmull()));
AddStep("Linear Overlapping 1 Repeat", () => testLinearOverlapping(1)); AddStep("Catmull Slider 1 Repeat", () => SetContents(() => testCatmull(1)));
AddStep("Linear Overlapping 2 Repeats", () => testLinearOverlapping(2)); AddStep("Catmull Slider 2 Repeats", () => SetContents(() => testCatmull(2)));
AddStep("Catmull Slider", () => testCatmull()); AddStep("Big Single, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset()));
AddStep("Catmull Slider 1 Repeat", () => testCatmull(1)); AddStep("Big 1 Repeat, Large StackOffset", () => SetContents(() => testSimpleBigLargeStackOffset(1)));
AddStep("Catmull Slider 2 Repeats", () => testCatmull(2));
AddStep("Big Single, Large StackOffset", () => testSimpleBigLargeStackOffset()); AddStep("Distance Overflow", () => SetContents(() => testDistanceOverflow()));
AddStep("Big 1 Repeat, Large StackOffset", () => testSimpleBigLargeStackOffset(1)); AddStep("Distance Overflow 1 Repeat", () => SetContents(() => testDistanceOverflow(1)));
AddStep("Distance Overflow", () => testDistanceOverflow());
AddStep("Distance Overflow 1 Repeat", () => testDistanceOverflow(1));
} }
private void testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats); private Drawable testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
private void testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10); private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
private void testDistanceOverflow(int repeats = 0) private Drawable testDistanceOverflow(int repeats = 0)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -120,22 +132,22 @@ namespace osu.Game.Rulesets.Osu.Tests
StackHeight = 10 StackHeight = 10
}; };
addSlider(slider, 2, 2); return createDrawable(slider, 2, 2);
} }
private void testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats); private Drawable testSimpleMedium(int repeats = 0) => createSlider(5, repeats: repeats);
private void testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats); private Drawable testSimpleSmall(int repeats = 0) => createSlider(7, repeats: repeats);
private void testSlowSpeed() => createSlider(speedMultiplier: 0.5); private Drawable testSlowSpeed() => createSlider(speedMultiplier: 0.5);
private void testShortSlowSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 0.5); private Drawable testShortSlowSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 0.5);
private void testHighSpeed(int repeats = 0) => createSlider(repeats: repeats, speedMultiplier: 15); private Drawable testHighSpeed(int repeats = 0) => createSlider(repeats: repeats, speedMultiplier: 15);
private void testShortHighSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 15); private Drawable testShortHighSpeed(int repeats = 0) => createSlider(distance: 100, repeats: repeats, speedMultiplier: 15);
private void createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2, int stackHeight = 0) private Drawable createSlider(float circleSize = 2, float distance = 400, int repeats = 0, double speedMultiplier = 2, int stackHeight = 0)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -151,10 +163,10 @@ namespace osu.Game.Rulesets.Osu.Tests
StackHeight = stackHeight StackHeight = stackHeight
}; };
addSlider(slider, circleSize, speedMultiplier); return createDrawable(slider, circleSize, speedMultiplier);
} }
private void testPerfect(int repeats = 0) private Drawable testPerfect(int repeats = 0)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -170,12 +182,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testLinear(int repeats = 0) => createLinear(repeats); private Drawable testLinear(int repeats = 0) => createLinear(repeats);
private void createLinear(int repeats) private Drawable createLinear(int repeats)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -194,12 +206,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testBezier(int repeats = 0) => createBezier(repeats); private Drawable testBezier(int repeats = 0) => createBezier(repeats);
private void createBezier(int repeats) private Drawable createBezier(int repeats)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -217,12 +229,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testLinearOverlapping(int repeats = 0) => createOverlapping(repeats); private Drawable testLinearOverlapping(int repeats = 0) => createOverlapping(repeats);
private void createOverlapping(int repeats) private Drawable createOverlapping(int repeats)
{ {
var slider = new Slider var slider = new Slider
{ {
@ -241,12 +253,12 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = createEmptySamples(repeats) NodeSamples = createEmptySamples(repeats)
}; };
addSlider(slider, 2, 3); return createDrawable(slider, 2, 3);
} }
private void testCatmull(int repeats = 0) => createCatmull(repeats); private Drawable testCatmull(int repeats = 0) => createCatmull(repeats);
private void createCatmull(int repeats = 0) private Drawable createCatmull(int repeats = 0)
{ {
var repeatSamples = new List<List<HitSampleInfo>>(); var repeatSamples = new List<List<HitSampleInfo>>();
for (int i = 0; i < repeats; i++) for (int i = 0; i < repeats; i++)
@ -267,7 +279,7 @@ namespace osu.Game.Rulesets.Osu.Tests
NodeSamples = repeatSamples NodeSamples = repeatSamples
}; };
addSlider(slider, 3, 1); return createDrawable(slider, 3, 1);
} }
private List<List<HitSampleInfo>> createEmptySamples(int repeats) private List<List<HitSampleInfo>> createEmptySamples(int repeats)
@ -278,7 +290,7 @@ namespace osu.Game.Rulesets.Osu.Tests
return repeatSamples; return repeatSamples;
} }
private void addSlider(Slider slider, float circleSize, double speedMultiplier) private Drawable createDrawable(Slider slider, float circleSize, double speedMultiplier)
{ {
var cpi = new ControlPointInfo(); var cpi = new ControlPointInfo();
cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier }); cpi.DifficultyPoints.Add(new DifficultyControlPoint { SpeedMultiplier = speedMultiplier });
@ -296,7 +308,7 @@ namespace osu.Game.Rulesets.Osu.Tests
drawable.OnNewResult += onNewResult; drawable.OnNewResult += onNewResult;
Add(drawable); return drawable;
} }
private float judgementOffsetDirection = 1; private float judgementOffsetDirection = 1;

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
Child = new Box Child = new Box
{ {
Size = new Vector2(width), Size = new Vector2(width),
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Alpha = 0.5f, Alpha = 0.5f,

View File

@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Origin = Anchor.Centre; Origin = Anchor.Centre;
InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon InternalChild = scaleContainer = new SkinnableDrawable("Play/osu/reversearrow", _ => new SpriteIcon

View File

@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
new TrianglesPiece new TrianglesPiece
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0.5f, Alpha = 0.5f,
} }
}; };

View File

@ -17,12 +17,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Alpha = 0; Alpha = 0;
Child = new SkinnableDrawable("Play/osu/hitcircle-explode", _ => new TrianglesPiece Child = new SkinnableDrawable("Play/osu/hitcircle-explode", _ => new TrianglesPiece
{ {
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0.2f, Alpha = 0.2f,
}, s => s.GetTexture("Play/osu/hitcircle") == null); }, s => s.GetTexture("Play/osu/hitcircle") == null);

View File

@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Alpha = 0; Alpha = 0;
Child = new SkinnableDrawable("Play/osu/hitcircle-flash", name => new CircularContainer Child = new SkinnableDrawable("Play/osu/hitcircle-flash", name => new CircularContainer

View File

@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Texture = textures.Get(name), Texture = textures.Get(name),
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0.5f Alpha = 0.5f
}, s => s.GetTexture("Play/osu/hitcircle") == null); }, s => s.GetTexture("Play/osu/hitcircle") == null);
} }

View File

@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
this.drawableSlider = drawableSlider; this.drawableSlider = drawableSlider;
this.slider = slider; this.slider = slider;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
@ -55,7 +55,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Child = new Container Child = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
// TODO: support skin filename animation (sliderb0, sliderb1...)
Child = new SkinnableDrawable("Play/osu/sliderball", _ => new DefaultSliderBall()), Child = new SkinnableDrawable("Play/osu/sliderball", _ => new DefaultSliderBall()),
} }
} }
@ -168,9 +167,20 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return action == OsuAction.LeftButton || action == OsuAction.RightButton; return action == OsuAction.LeftButton || action == OsuAction.RightButton;
} }
private Vector2? lastPosition;
public void UpdateProgress(double completionProgress) public void UpdateProgress(double completionProgress)
{ {
Position = slider.CurvePositionAt(completionProgress); var newPos = slider.CurvePositionAt(completionProgress);
var diff = lastPosition.HasValue ? lastPosition.Value - newPos : newPos - slider.CurvePositionAt(completionProgress + 0.01f);
if (diff == Vector2.Zero)
return;
Position = newPos;
Rotation = -90 + (float)(-Math.Atan2(diff.X, diff.Y) * 180 / Math.PI);
lastPosition = newPos;
} }
private class FollowCircleContainer : Container private class FollowCircleContainer : Container
@ -190,7 +200,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Masking = true, Masking = true,
BorderThickness = 5, BorderThickness = 5,
BorderColour = Color4.Orange, BorderColour = Color4.Orange,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Child = new Box Child = new Box
{ {
Colour = Color4.Orange, Colour = Color4.Orange,

View File

@ -4,7 +4,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
Origin = Anchor.Centre, Origin = Anchor.Centre,
Alpha = 0, Alpha = 0,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Masking = true, Masking = true,
Children = new[] Children = new[]
{ {
@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
BorderThickness = target_ring_thick_border, BorderThickness = target_ring_thick_border,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box new Box

View File

@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.White, Colour = Color4.White,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0, Alpha = 0,
AlwaysPresent = true AlwaysPresent = true
} }

View File

@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Taiko.UI
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0, Alpha = 0,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
}, },
centre = new Sprite centre = new Sprite
{ {
@ -124,7 +124,7 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Size = new Vector2(0.7f), Size = new Vector2(0.7f),
Alpha = 0, Alpha = 0,
Blending = BlendingMode.Additive Blending = BlendingParameters.Additive
} }
}; };
} }

View File

@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit, FillMode = FillMode.Fit,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
}, },
HitTarget = new HitTarget HitTarget = new HitTarget
{ {
@ -127,14 +127,14 @@ namespace osu.Game.Rulesets.Taiko.UI
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit, FillMode = FillMode.Fit,
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
Blending = BlendingMode.Additive Blending = BlendingParameters.Additive
}, },
judgementContainer = new JudgementContainer<DrawableTaikoJudgement> judgementContainer = new JudgementContainer<DrawableTaikoJudgement>
{ {
Name = "Judgements", Name = "Judgements",
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
Margin = new MarginPadding { Left = HIT_TARGET_OFFSET }, Margin = new MarginPadding { Left = HIT_TARGET_OFFSET },
Blending = BlendingMode.Additive Blending = BlendingParameters.Additive
}, },
} }
}, },

View File

@ -17,6 +17,8 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
private bool exitAction; private bool exitAction;
protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {

View File

@ -135,6 +135,9 @@ namespace osu.Game.Tests.Visual.Online
}); });
downloadAssert(true); downloadAssert(true);
AddStep("show many difficulties", () => overlay.ShowBeatmapSet(createManyDifficultiesBeatmapSet()));
downloadAssert(true);
} }
[Test] [Test]
@ -222,6 +225,56 @@ namespace osu.Game.Tests.Visual.Online
AddStep(@"show without reload", overlay.Show); AddStep(@"show without reload", overlay.Show);
} }
private BeatmapSetInfo createManyDifficultiesBeatmapSet()
{
var beatmaps = new List<BeatmapInfo>();
for (int i = 1; i < 41; i++)
{
beatmaps.Add(new BeatmapInfo
{
OnlineBeatmapID = i * 10,
Version = $"Test #{i}",
Ruleset = Ruleset.Value,
StarDifficulty = 2 + i * 0.1,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
},
OnlineInfo = new BeatmapOnlineInfo(),
Metrics = new BeatmapMetrics
{
Fails = Enumerable.Range(1, 100).Select(j => j % 12 - 6).ToArray(),
Retries = Enumerable.Range(-2, 100).Select(j => j % 12 - 6).ToArray(),
},
});
}
return new BeatmapSetInfo
{
OnlineBeatmapSetID = 123,
Metadata = new BeatmapMetadata
{
Title = @"many difficulties beatmap",
Artist = @"none",
Author = new User
{
Username = @"BanchoBot",
Id = 3,
},
},
OnlineInfo = new BeatmapSetOnlineInfo
{
Preview = @"https://b.ppy.sh/preview/123.mp3",
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
},
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = beatmaps,
};
}
private void downloadAssert(bool shown) private void downloadAssert(bool shown)
{ {
AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown); AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.DownloadButtonsVisible == shown);

View File

@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Overlays.Direct; using osu.Game.Overlays.Direct;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;
@ -24,7 +23,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(IconPill) typeof(IconPill)
}; };
private BeatmapSetInfo getUndownloadableBeatmapSet(RulesetInfo ruleset) => new BeatmapSetInfo private BeatmapSetInfo getUndownloadableBeatmapSet() => new BeatmapSetInfo
{ {
OnlineBeatmapSetID = 123, OnlineBeatmapSetID = 123,
Metadata = new BeatmapMetadata Metadata = new BeatmapMetadata
@ -56,23 +55,62 @@ namespace osu.Game.Tests.Visual.Online
{ {
new BeatmapInfo new BeatmapInfo
{ {
Ruleset = ruleset, Ruleset = Ruleset.Value,
Version = "Test", Version = "Test",
StarDifficulty = 6.42, StarDifficulty = 6.42,
} }
} }
}; };
[BackgroundDependencyLoader] private BeatmapSetInfo getManyDifficultiesBeatmapSet(RulesetStore rulesets)
private void load()
{ {
var ruleset = new OsuRuleset().RulesetInfo; var beatmaps = new List<BeatmapInfo>();
var normal = CreateWorkingBeatmap(ruleset).BeatmapSetInfo; for (int i = 0; i < 100; i++)
{
beatmaps.Add(new BeatmapInfo
{
Ruleset = rulesets.GetRuleset(i % 4),
StarDifficulty = 2 + i % 4 * 2,
BaseDifficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
}
});
}
return new BeatmapSetInfo
{
OnlineBeatmapSetID = 1,
Metadata = new BeatmapMetadata
{
Title = "many difficulties beatmap",
Artist = "test",
Author = new User
{
Username = "BanchoBot",
Id = 3,
}
},
OnlineInfo = new BeatmapSetOnlineInfo
{
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
},
Beatmaps = beatmaps,
};
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
var normal = CreateWorkingBeatmap(Ruleset.Value).BeatmapSetInfo;
normal.OnlineInfo.HasVideo = true; normal.OnlineInfo.HasVideo = true;
normal.OnlineInfo.HasStoryboard = true; normal.OnlineInfo.HasStoryboard = true;
var undownloadable = getUndownloadableBeatmapSet(ruleset); var undownloadable = getUndownloadableBeatmapSet();
var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets);
Child = new BasicScrollContainer Child = new BasicScrollContainer
{ {
@ -81,15 +119,17 @@ namespace osu.Game.Tests.Visual.Online
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical, Direction = FillDirection.Full,
Padding = new MarginPadding(20), Padding = new MarginPadding(20),
Spacing = new Vector2(0, 20), Spacing = new Vector2(5, 20),
Children = new Drawable[] Children = new Drawable[]
{ {
new DirectGridPanel(normal), new DirectGridPanel(normal),
new DirectListPanel(normal),
new DirectGridPanel(undownloadable), new DirectGridPanel(undownloadable),
new DirectGridPanel(manyDifficulties),
new DirectListPanel(normal),
new DirectListPanel(undownloadable), new DirectListPanel(undownloadable),
new DirectListPanel(manyDifficulties),
}, },
}, },
}; };

View File

@ -516,6 +516,7 @@ namespace osu.Game.Tests.Visual.SongSelect
OnlineBeatmapID = b * 10, OnlineBeatmapID = b * 10,
Path = $"extra{b}.osu", Path = $"extra{b}.osu",
Version = $"Extra {b}", Version = $"Extra {b}",
Ruleset = rulesets.GetRuleset((b - 1) % 4),
StarDifficulty = 2, StarDifficulty = 2,
BaseDifficulty = new BeatmapDifficulty BaseDifficulty = new BeatmapDifficulty
{ {

View File

@ -249,7 +249,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Size = new Vector2(50); Size = new Vector2(50);
Masking = true; Masking = true;
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
Alpha = 0.5f; Alpha = 0.5f;
Child = new Box { RelativeSizeAxes = Axes.Both }; Child = new Box { RelativeSizeAxes = Axes.Both };

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
@ -12,7 +13,13 @@ namespace osu.Game.Tests.Visual.UserInterface
{ {
public class TestSceneHoldToConfirmOverlay : OsuTestScene public class TestSceneHoldToConfirmOverlay : OsuTestScene
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(ExitConfirmOverlay) }; protected override double TimePerAction => 100; // required for the early exit test, since hold-to-confirm delay is 200ms
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(ExitConfirmOverlay),
typeof(HoldToConfirmContainer),
};
public TestSceneHoldToConfirmOverlay() public TestSceneHoldToConfirmOverlay()
{ {

View File

@ -5,7 +5,7 @@
<PackageReference Include="DeepEqual" Version="2.0.0" /> <PackageReference Include="DeepEqual" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" /> <PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">

View File

@ -7,7 +7,7 @@
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" /> <PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="NUnit" Version="3.12.0" /> <PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.14.0" /> <PackageReference Include="NUnit3TestAdapter" Version="3.15.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>

View File

@ -125,7 +125,7 @@ namespace osu.Game.Tournament.Components
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Gray, Colour = Color4.Gray,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0, Alpha = 0,
}, },
}); });

View File

@ -129,6 +129,23 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public List<ScoreInfo> Scores { get; set; } public List<ScoreInfo> Scores { get; set; }
[JsonIgnore]
public DifficultyRating DifficultyRating
{
get
{
var rating = StarDifficulty;
if (rating < 2.0) return DifficultyRating.Easy;
if (rating < 2.7) return DifficultyRating.Normal;
if (rating < 4.0) return DifficultyRating.Hard;
if (rating < 5.3) return DifficultyRating.Insane;
if (rating < 6.5) return DifficultyRating.Expert;
return DifficultyRating.ExpertPlus;
}
}
public override string ToString() => $"{Metadata} [{Version}]".Trim(); public override string ToString() => $"{Metadata} [{Version}]".Trim();
public bool Equals(BeatmapInfo other) public bool Equals(BeatmapInfo other)

View File

@ -138,19 +138,15 @@ namespace osu.Game.Beatmaps
protected override Skin GetSkin() protected override Skin GetSkin()
{ {
Skin skin;
try try
{ {
skin = new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager); return new LegacyBeatmapSkin(BeatmapInfo, store, AudioManager);
} }
catch (Exception e) catch (Exception e)
{ {
Logger.Error(e, "Skin failed to load"); Logger.Error(e, "Skin failed to load");
skin = new DefaultSkin(); return null;
} }
return skin;
} }
} }
} }

View File

@ -0,0 +1,15 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Beatmaps
{
public enum DifficultyRating
{
Easy,
Normal,
Hard,
Insane,
Expert,
ExpertPlus
}
}

View File

@ -1,85 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
public abstract class DifficultyColouredContainer : Container, IHasAccentColour
{
public Color4 AccentColour { get; set; }
private readonly BeatmapInfo beatmap;
private OsuColour palette;
protected DifficultyColouredContainer(BeatmapInfo beatmap)
{
this.beatmap = beatmap;
}
[BackgroundDependencyLoader]
private void load(OsuColour palette)
{
if (palette == null)
throw new ArgumentNullException(nameof(palette));
this.palette = palette;
AccentColour = getColour(beatmap);
}
private enum DifficultyRating
{
Easy,
Normal,
Hard,
Insane,
Expert,
ExpertPlus
}
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
{
if (beatmap == null)
throw new ArgumentNullException(nameof(beatmap));
var rating = beatmap.StarDifficulty;
if (rating < 2.0) return DifficultyRating.Easy;
if (rating < 2.7) return DifficultyRating.Normal;
if (rating < 4.0) return DifficultyRating.Hard;
if (rating < 5.3) return DifficultyRating.Insane;
if (rating < 6.5) return DifficultyRating.Expert;
return DifficultyRating.ExpertPlus;
}
private Color4 getColour(BeatmapInfo beatmap)
{
switch (getDifficultyRating(beatmap))
{
case DifficultyRating.Easy:
return palette.Green;
default:
case DifficultyRating.Normal:
return palette.Blue;
case DifficultyRating.Hard:
return palette.Yellow;
case DifficultyRating.Insane:
return palette.Pink;
case DifficultyRating.Expert:
return palette.Purple;
case DifficultyRating.ExpertPlus:
return palette.Gray0;
}
}
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
@ -6,35 +6,58 @@ using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables namespace osu.Game.Beatmaps.Drawables
{ {
public class DifficultyIcon : DifficultyColouredContainer public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip
{ {
private readonly BeatmapInfo beatmap;
private readonly RulesetInfo ruleset; private readonly RulesetInfo ruleset;
public DifficultyIcon(BeatmapInfo beatmap, RulesetInfo ruleset = null) private readonly Container iconContainer;
: base(beatmap)
/// <summary>
/// Size of this difficulty icon.
/// </summary>
public new Vector2 Size
{ {
if (beatmap == null) get => iconContainer.Size;
throw new ArgumentNullException(nameof(beatmap)); set => iconContainer.Size = value;
this.ruleset = ruleset ?? beatmap.Ruleset;
Size = new Vector2(20);
} }
[BackgroundDependencyLoader] public DifficultyIcon(BeatmapInfo beatmap, RulesetInfo ruleset = null, bool shouldShowTooltip = true)
private void load()
{ {
Children = new Drawable[] this.beatmap = beatmap ?? throw new ArgumentNullException(nameof(beatmap));
this.ruleset = ruleset ?? beatmap.Ruleset;
if (shouldShowTooltip)
TooltipContent = beatmap;
AutoSizeAxes = Axes.Both;
InternalChild = iconContainer = new Container { Size = new Vector2(20f) };
}
public string TooltipText { get; set; }
public ITooltip GetCustomTooltip() => new DifficultyIconTooltip();
public object TooltipContent { get; set; }
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
iconContainer.Children = new Drawable[]
{ {
new CircularContainer new CircularContainer
{ {
@ -52,7 +75,7 @@ namespace osu.Game.Beatmaps.Drawables
Child = new Box Child = new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = AccentColour, Colour = colours.ForDifficultyRating(beatmap.DifficultyRating),
}, },
}, },
new ConstrainedIconContainer new ConstrainedIconContainer
@ -65,5 +88,96 @@ namespace osu.Game.Beatmaps.Drawables
} }
}; };
} }
private class DifficultyIconTooltip : VisibilityContainer, ITooltip
{
private readonly OsuSpriteText difficultyName, starRating;
private readonly Box background;
private readonly FillFlowContainer difficultyFlow;
public DifficultyIconTooltip()
{
AutoSizeAxes = Axes.Both;
Masking = true;
CornerRadius = 5;
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
AutoSizeDuration = 200,
AutoSizeEasing = Easing.OutQuint,
Direction = FillDirection.Vertical,
Padding = new MarginPadding(10),
Children = new Drawable[]
{
difficultyName = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold),
},
difficultyFlow = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Direction = FillDirection.Horizontal,
Children = new Drawable[]
{
starRating = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
},
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Left = 4 },
Icon = FontAwesome.Solid.Star,
Size = new Vector2(12),
},
}
}
}
}
};
}
private OsuColour colours;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
this.colours = colours;
background.Colour = colours.Gray3;
}
public bool SetContent(object content)
{
if (!(content is BeatmapInfo beatmap))
return false;
difficultyName.Text = beatmap.Version;
starRating.Text = $"{beatmap.StarDifficulty:0.##}";
difficultyFlow.Colour = colours.ForDifficultyRating(beatmap.DifficultyRating);
return true;
}
public void Move(Vector2 pos) => Position = pos;
protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
}
} }
} }

View File

@ -0,0 +1,37 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osuTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
/// <summary>
/// A difficulty icon that contains a counter on the right-side of it.
/// </summary>
/// <remarks>
/// Used in cases when there are too many difficulty icons to show.
/// </remarks>
public class GroupedDifficultyIcon : DifficultyIcon
{
public GroupedDifficultyIcon(List<BeatmapInfo> beatmaps, RulesetInfo ruleset, Color4 counterColour)
: base(beatmaps.OrderBy(b => b.StarDifficulty).Last(), ruleset, false)
{
AddInternal(new OsuSpriteText
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Padding = new MarginPadding { Left = Size.X },
Margin = new MarginPadding { Left = 2, Right = 5 },
Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold),
Text = beatmaps.Count.ToString(),
Colour = counterColour,
});
}
}
}

View File

@ -246,7 +246,7 @@ namespace osu.Game.Beatmaps.Formats
switch (type) switch (type)
{ {
case "A": case "A":
timelineGroup?.BlendingMode.Add(easing, startTime, endTime, BlendingMode.Additive, startTime == endTime ? BlendingMode.Additive : BlendingMode.Inherit); timelineGroup?.BlendingParameters.Add(easing, startTime, endTime, BlendingParameters.Additive, startTime == endTime ? BlendingParameters.Additive : BlendingParameters.Inherit);
break; break;
case "H": case "H":

View File

@ -12,9 +12,11 @@ namespace osu.Game.Graphics.Containers
{ {
public Action Action; public Action Action;
private const int activate_delay = 400; private const int default_activation_delay = 200;
private const int fadeout_delay = 200; private const int fadeout_delay = 200;
private readonly double activationDelay;
private bool fired; private bool fired;
private bool confirming; private bool confirming;
@ -25,13 +27,22 @@ namespace osu.Game.Graphics.Containers
public Bindable<double> Progress = new BindableDouble(); public Bindable<double> Progress = new BindableDouble();
/// <summary>
/// Create a new instance.
/// </summary>
/// <param name="activationDelay">The time requried before an action is confirmed.</param>
protected HoldToConfirmContainer(double activationDelay = default_activation_delay)
{
this.activationDelay = activationDelay;
}
protected void BeginConfirm() protected void BeginConfirm()
{ {
if (confirming || (!AllowMultipleFires && fired)) return; if (confirming || (!AllowMultipleFires && fired)) return;
confirming = true; confirming = true;
this.TransformBindableTo(Progress, 1, activate_delay * (1 - Progress.Value), Easing.Out).OnComplete(_ => Confirm()); this.TransformBindableTo(Progress, 1, activationDelay * (1 - Progress.Value), Easing.Out).OnComplete(_ => Confirm());
} }
protected virtual void Confirm() protected virtual void Confirm()

View File

@ -15,6 +15,7 @@ using osu.Game.Overlays;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers
{ {
[Cached(typeof(IPreviewTrackOwner))]
public abstract class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction> public abstract class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction>
{ {
private SampleChannel samplePopIn; private SampleChannel samplePopIn;
@ -38,13 +39,6 @@ namespace osu.Game.Graphics.Containers
protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All); protected readonly Bindable<OverlayActivation> OverlayActivationMode = new Bindable<OverlayActivation>(OverlayActivation.All);
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
dependencies.CacheAs<IPreviewTrackOwner>(this);
return dependencies;
}
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(AudioManager audio) private void load(AudioManager audio)
{ {

View File

@ -98,7 +98,7 @@ namespace osu.Game.Graphics.Containers
public OsuScrollbar(Direction scrollDir) public OsuScrollbar(Direction scrollDir)
: base(scrollDir) : base(scrollDir)
{ {
Blending = BlendingMode.Additive; Blending = BlendingParameters.Additive;
CornerRadius = 5; CornerRadius = 5;

View File

@ -150,7 +150,7 @@ namespace osu.Game.Graphics.Cursor
}, },
AdditiveLayer = new Sprite AdditiveLayer = new Sprite
{ {
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Colour = colour.Pink, Colour = colour.Pink,
Alpha = 0, Alpha = 0,
Texture = textures.Get(@"Cursor/menu-cursor-additive"), Texture = textures.Get(@"Cursor/menu-cursor-additive"),

View File

@ -30,22 +30,24 @@ namespace osu.Game.Graphics.Cursor
private readonly OsuSpriteText text; private readonly OsuSpriteText text;
private bool instantMovement = true; private bool instantMovement = true;
public override string TooltipText public override bool SetContent(object content)
{ {
set if (!(content is string contentString))
return false;
if (contentString == text.Text) return true;
text.Text = contentString;
if (IsPresent)
{ {
if (value == text.Text) return; AutoSizeDuration = 250;
background.FlashColour(OsuColour.Gray(0.4f), 1000, Easing.OutQuint);
text.Text = value;
if (IsPresent)
{
AutoSizeDuration = 250;
background.FlashColour(OsuColour.Gray(0.4f), 1000, Easing.OutQuint);
}
else
AutoSizeDuration = 0;
} }
else
AutoSizeDuration = 0;
return true;
} }
public OsuTooltip() public OsuTooltip()

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using osu.Game.Beatmaps;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Graphics namespace osu.Game.Graphics
@ -37,6 +38,31 @@ namespace osu.Game.Graphics
} }
} }
public Color4 ForDifficultyRating(DifficultyRating difficulty)
{
switch (difficulty)
{
case DifficultyRating.Easy:
return Green;
default:
case DifficultyRating.Normal:
return Blue;
case DifficultyRating.Hard:
return Yellow;
case DifficultyRating.Insane:
return Pink;
case DifficultyRating.Expert:
return Purple;
case DifficultyRating.ExpertPlus:
return Gray0;
}
}
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less // See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = FromHex(@"eeeeff"); public readonly Color4 PurpleLighter = FromHex(@"eeeeff");
public readonly Color4 PurpleLight = FromHex(@"aa88ff"); public readonly Color4 PurpleLight = FromHex(@"aa88ff");

View File

@ -56,7 +56,7 @@ namespace osu.Game.Graphics.Sprites
BlurSigma = new Vector2(4), BlurSigma = new Vector2(4),
CacheDrawnFrameBuffer = true, CacheDrawnFrameBuffer = true,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Size = new Vector2(3f), Size = new Vector2(3f),
Children = new[] Children = new[]
{ {

View File

@ -254,7 +254,7 @@ namespace osu.Game.Graphics.UserInterface
colourContainer.Add(flash); colourContainer.Add(flash);
flash.Colour = ButtonColour; flash.Colour = ButtonColour;
flash.Blending = BlendingMode.Additive; flash.Blending = BlendingParameters.Additive;
flash.Alpha = 0.3f; flash.Alpha = 0.3f;
flash.FadeOutFromOne(click_duration); flash.FadeOutFromOne(click_duration);
flash.Expire(); flash.Expire();

View File

@ -64,7 +64,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = HoverColour, Colour = HoverColour,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0, Alpha = 0,
}, },
} }

View File

@ -39,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
hover = new Box hover = new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Colour = Color4.White.Opacity(0.1f), Colour = Color4.White.Opacity(0.1f),
Alpha = 0, Alpha = 0,
Depth = -1 Depth = -1

View File

@ -72,17 +72,11 @@ namespace osu.Game.Graphics.UserInterface
Current.DisabledChanged += disabled => labelText.Alpha = Nub.Alpha = disabled ? 0.3f : 1; Current.DisabledChanged += disabled => labelText.Alpha = Nub.Alpha = disabled ? 0.3f : 1;
} }
protected override void LoadComplete() [BackgroundDependencyLoader]
private void load(AudioManager audio)
{ {
base.LoadComplete(); sampleChecked = audio.Samples.Get(@"UI/check-on");
sampleUnchecked = audio.Samples.Get(@"UI/check-off");
Current.ValueChanged += enabled =>
{
if (enabled.NewValue)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
};
} }
protected override bool OnHover(HoverEvent e) protected override bool OnHover(HoverEvent e)
@ -99,11 +93,13 @@ namespace osu.Game.Graphics.UserInterface
base.OnHoverLost(e); base.OnHoverLost(e);
} }
[BackgroundDependencyLoader] protected override void OnUserChange(bool value)
private void load(AudioManager audio)
{ {
sampleChecked = audio.Samples.Get(@"UI/check-on"); base.OnUserChange(value);
sampleUnchecked = audio.Samples.Get(@"UI/check-off"); if (value)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
} }
} }
} }

View File

@ -122,6 +122,7 @@ namespace osu.Game.Online.Chat
return new LinkDetails(LinkAction.OpenBeatmapSet, args[3]); return new LinkDetails(LinkAction.OpenBeatmapSet, args[3]);
case "u": case "u":
case "users":
return new LinkDetails(LinkAction.OpenUserProfile, args[3]); return new LinkDetails(LinkAction.OpenUserProfile, args[3]);
} }
} }

View File

@ -91,7 +91,8 @@ namespace osu.Game.Overlays.BeatmapSet
{ {
difficulties = new DifficultiesContainer difficulties = new DifficultiesContainer
{ {
AutoSizeAxes = Axes.Both, 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) },
OnLostHover = () => OnLostHover = () =>
{ {
@ -234,7 +235,7 @@ namespace osu.Game.Overlays.BeatmapSet
Colour = Color4.Black.Opacity(0.5f), Colour = Color4.Black.Opacity(0.5f),
}, },
}, },
icon = new DifficultyIcon(beatmap) icon = new DifficultyIcon(beatmap, shouldShowTooltip: false)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -151,7 +151,7 @@ namespace osu.Game.Overlays.Direct
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Height = 20, Height = 20,
Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding },
Children = GetDifficultyIcons(), Children = GetDifficultyIcons(colours),
}, },
}, },
}, },

View File

@ -129,7 +129,7 @@ namespace osu.Game.Overlays.Direct
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Height = 20, Height = 20,
Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding }, Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding },
Children = GetDifficultyIcons(), Children = GetDifficultyIcons(colours),
}, },
}, },
}, },

View File

@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Direct
public readonly BeatmapSetInfo SetInfo; public readonly BeatmapSetInfo SetInfo;
private const double hover_transition_time = 400; private const double hover_transition_time = 400;
private const int maximum_difficulty_icons = 15;
private Container content; private Container content;
@ -138,12 +139,18 @@ namespace osu.Game.Overlays.Direct
}; };
} }
protected List<DifficultyIcon> GetDifficultyIcons() protected List<DifficultyIcon> GetDifficultyIcons(OsuColour colours)
{ {
var icons = new List<DifficultyIcon>(); var icons = new List<DifficultyIcon>();
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty)) if (SetInfo.Beatmaps.Count > maximum_difficulty_icons)
icons.Add(new DifficultyIcon(b)); {
foreach (var ruleset in SetInfo.Beatmaps.Select(b => b.Ruleset).Distinct())
icons.Add(new GroupedDifficultyIcon(SetInfo.Beatmaps.FindAll(b => b.Ruleset.Equals(ruleset)), ruleset, this is DirectListPanel ? Color4.White : colours.Gray5));
}
else
foreach (var b in SetInfo.Beatmaps.OrderBy(beatmap => beatmap.StarDifficulty))
icons.Add(new DifficultyIcon(b));
return icons; return icons;
} }

View File

@ -92,6 +92,15 @@ namespace osu.Game.Overlays
}); });
} }
/// <summary>
/// Start playing the current track (if not already playing).
/// </summary>
public void Play()
{
if (!IsPlaying)
TogglePause();
}
/// <summary> /// <summary>
/// Toggle pause / play. /// Toggle pause / play.
/// </summary> /// </summary>

View File

@ -140,6 +140,9 @@ namespace osu.Game.Overlays.Profile.Header
{ {
if (string.IsNullOrEmpty(content)) return; if (string.IsNullOrEmpty(content)) return;
// newlines could be contained in API returned user content.
content = content.Replace("\n", " ");
bottomLinkContainer.AddIcon(icon, text => bottomLinkContainer.AddIcon(icon, text =>
{ {
text.Font = text.Font.With(size: 10); text.Font = text.Font.With(size: 10);

View File

@ -196,17 +196,30 @@ namespace osu.Game.Overlays.Profile.Header.Components
} }
} }
public string TooltipText => Statistics.Value?.Ranks.Global == null ? "" : $"#{ranks[dayIndex].Value:#,##0}|{ranked_days - ranks[dayIndex].Key + 1}"; public object TooltipContent
{
get
{
if (Statistics.Value?.Ranks.Global == null)
return null;
var days = ranked_days - ranks[dayIndex].Key + 1;
return new TooltipDisplayContent
{
Rank = $"#{ranks[dayIndex].Value:#,##0}",
Time = days == 0 ? "now" : $"{days} days ago"
};
}
}
public ITooltip GetCustomTooltip() => new RankGraphTooltip(); public ITooltip GetCustomTooltip() => new RankGraphTooltip();
public class RankGraphTooltip : VisibilityContainer, ITooltip private class RankGraphTooltip : VisibilityContainer, ITooltip
{ {
private readonly OsuSpriteText globalRankingText, timeText; private readonly OsuSpriteText globalRankingText, timeText;
private readonly Box background; private readonly Box background;
public string TooltipText { get; set; }
public RankGraphTooltip() public RankGraphTooltip()
{ {
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
@ -260,11 +273,14 @@ namespace osu.Game.Overlays.Profile.Header.Components
background.Colour = colours.GreySeafoamDark; background.Colour = colours.GreySeafoamDark;
} }
public void Refresh() public bool SetContent(object content)
{ {
var info = TooltipText.Split('|'); if (!(content is TooltipDisplayContent info))
globalRankingText.Text = info[0]; return false;
timeText.Text = info[1] == "0" ? "now" : $"{info[1]} days ago";
globalRankingText.Text = info.Rank;
timeText.Text = info.Time;
return true;
} }
private bool instantMove = true; private bool instantMove = true;
@ -284,5 +300,11 @@ namespace osu.Game.Overlays.Profile.Header.Components
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
} }
private class TooltipDisplayContent
{
public string Rank;
public string Time;
}
} }
} }

View File

@ -46,8 +46,11 @@ namespace osu.Game.Overlays.Profile.Sections.Beatmaps
if (!s.OnlineBeatmapSetID.HasValue) if (!s.OnlineBeatmapSetID.HasValue)
continue; continue;
var panel = new DirectGridPanel(s.ToBeatmapSet(Rulesets)); ItemsContainer.Add(new DirectGridPanel(s.ToBeatmapSet(Rulesets))
ItemsContainer.Add(panel); {
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
});
} }
}); });

View File

@ -124,14 +124,12 @@ namespace osu.Game.Overlays.Profile.Sections
private class ChevronIcon : SpriteIcon private class ChevronIcon : SpriteIcon
{ {
private const int bottom_margin = 2;
private const int icon_size = 8; private const int icon_size = 8;
public ChevronIcon() public ChevronIcon()
{ {
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
Margin = new MarginPadding { Bottom = bottom_margin };
Size = new Vector2(icon_size); Size = new Vector2(icon_size);
Icon = FontAwesome.Solid.ChevronDown; Icon = FontAwesome.Solid.ChevronDown;
} }

View File

@ -57,7 +57,6 @@ namespace osu.Game.Overlays
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Y = -15,
Size = new Vector2(15), Size = new Vector2(15),
Shadow = true, Shadow = true,
Icon = FontAwesome.Solid.ChevronLeft Icon = FontAwesome.Solid.ChevronLeft

View File

@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Toolbar
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(80).Opacity(180), Colour = OsuColour.Gray(80).Opacity(180),
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Alpha = 0, Alpha = 0,
}, },
Flow = new FillFlowContainer Flow = new FillFlowContainer

View File

@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Toolbar
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(150).Opacity(180), Colour = OsuColour.Gray(150).Opacity(180),
Blending = BlendingMode.Additive, Blending = BlendingParameters.Additive,
Depth = 2, Depth = 2,
Alpha = 0, Alpha = 0,
}); });

View File

@ -65,16 +65,15 @@ namespace osu.Game.Overlays.Volume
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(20),
} }
}); });
Current.ValueChanged += muted => Current.BindValueChanged(muted =>
{ {
icon.Icon = muted.NewValue ? FontAwesome.Solid.VolumeMute : FontAwesome.Solid.VolumeUp; icon.Icon = muted.NewValue ? FontAwesome.Solid.VolumeMute : FontAwesome.Solid.VolumeUp;
}; icon.Size = new Vector2(muted.NewValue ? 18 : 20);
icon.Margin = new MarginPadding { Right = muted.NewValue ? 2 : 0 };
Current.TriggerChange(); }, true);
} }
protected override bool OnHover(HoverEvent e) protected override bool OnHover(HoverEvent e)

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -57,7 +58,12 @@ namespace osu.Game.Rulesets.Edit
this.drawableRuleset = drawableRuleset; this.drawableRuleset = drawableRuleset;
InternalChild = drawableRuleset; InternalChild = drawableRuleset;
}
[BackgroundDependencyLoader]
private void load()
{
drawableRuleset.FrameStablePlayback = false;
Playfield.DisplayJudgements.Value = false; Playfield.DisplayJudgements.Value = false;
} }

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