Merge branch 'master' into add-access-to-skin-legacy-version

This commit is contained in:
Dan Balasescu
2019-11-25 12:40:01 +09:00
committed by GitHub
161 changed files with 1699 additions and 451 deletions

View File

@ -2,3 +2,4 @@ M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use obj
M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead. M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead. M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead.
T:System.IComparable;Don't use non-generic IComparable. Use generic version instead. T:System.IComparable;Don't use non-generic IComparable. Use generic version instead.
T:osu.Framework.Graphics.Sprites.SpriteText.#ctor;Use OsuSpriteText.

View File

@ -10,12 +10,14 @@
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies> <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidApplication>True</AndroidApplication> <AndroidApplication>True</AndroidApplication>
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType> <AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<TargetFrameworkVersion>v9.0</TargetFrameworkVersion> <TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk> <AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a</AndroidSupportedAbis> <AndroidSupportedAbis>armeabi-v7a;x86;arm64-v8a</AndroidSupportedAbis>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent> <AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<MandroidI18n>cjk,mideast,other,rare,west</MandroidI18n> <MandroidI18n>cjk,mideast,other,rare,west</MandroidI18n>
<AndroidHttpClientHandlerType>System.Net.Http.HttpClientHandler</AndroidHttpClientHandlerType>
<AndroidTlsProvider>legacy</AndroidTlsProvider>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>SdkOnly</AndroidLinkMode>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
</PropertyGroup> </PropertyGroup>
@ -53,6 +55,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1112.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2019.1122.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" package="sh.ppy.osulazer" android:installLocation="auto" android:versionName="0.1.0"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" package="sh.ppy.osulazer" android:installLocation="auto" android:versionName="0.1.0">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Catch.Tests.Android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Catch.Tests.Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!catch Test" /> <application android:allowBackup="true" android:supportsRtl="true" android:label="osu!catch Test" />
</manifest> </manifest>

View File

@ -11,12 +11,12 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Catch.Tests
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Blue Colour = Color4.Blue
}, },
new SpriteText new OsuSpriteText
{ {
Text = "custom" Text = "custom"
} }

View File

@ -8,7 +8,6 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osuTK;
using osu.Game.Rulesets.Catch.MathUtils; using osu.Game.Rulesets.Catch.MathUtils;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -78,7 +77,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
catchObject.XOffset = 0; catchObject.XOffset = 0;
if (catchObject is TinyDroplet) if (catchObject is TinyDroplet)
catchObject.XOffset = MathHelper.Clamp(rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH, -catchObject.X, 1 - catchObject.X); catchObject.XOffset = Math.Clamp(rng.Next(-20, 20) / CatchPlayfield.BASE_WIDTH, -catchObject.X, 1 - catchObject.X);
else if (catchObject is Droplet) else if (catchObject is Droplet)
rng.Next(); // osu!stable retrieved a random droplet rotation rng.Next(); // osu!stable retrieved a random droplet rotation
} }
@ -230,7 +229,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
else else
{ {
currentObject.DistanceToHyperDash = distanceToHyper; currentObject.DistanceToHyperDash = distanceToHyper;
lastExcess = MathHelper.Clamp(distanceToHyper, 0, halfCatcherWidth); lastExcess = Math.Clamp(distanceToHyper, 0, halfCatcherWidth);
} }
lastDirection = thisDirection; lastDirection = thisDirection;

View File

@ -10,7 +10,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Scoring.Legacy; using osu.Game.Scoring.Legacy;
using osuTK;
namespace osu.Game.Rulesets.Catch.Difficulty namespace osu.Game.Rulesets.Catch.Difficulty
{ {
@ -56,7 +55,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
// Longer maps are worth more // Longer maps are worth more
float lengthBonus = float lengthBonus =
0.95f + 0.4f * Math.Min(1.0f, numTotalHits / 3000.0f) + 0.95f + 0.4f * Math.Min(1.0f, numTotalHits / 3000.0f) +
(numTotalHits > 3000 ? (float)Math.Log10(numTotalHits / 3000.0f) * 0.5f : 0.0f); (numTotalHits > 3000 ? MathF.Log10(numTotalHits / 3000.0f) * 0.5f : 0.0f);
// Longer maps are worth more // Longer maps are worth more
value *= lengthBonus; value *= lengthBonus;
@ -96,7 +95,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
return value; return value;
} }
private float accuracy() => totalHits() == 0 ? 0 : MathHelper.Clamp((float)totalSuccessfulHits() / totalHits(), 0f, 1f); private float accuracy() => totalHits() == 0 ? 0 : Math.Clamp((float)totalSuccessfulHits() / totalHits(), 0f, 1f);
private int totalHits() => tinyTicksHit + ticksHit + fruitsHit + misses + tinyTicksMissed; private int totalHits() => tinyTicksHit + ticksHit + fruitsHit + misses + tinyTicksMissed;
private int totalSuccessfulHits() => tinyTicksHit + ticksHit + fruitsHit; private int totalSuccessfulHits() => tinyTicksHit + ticksHit + fruitsHit;
private int totalComboHits() => misses + ticksHit + fruitsHit; private int totalComboHits() => misses + ticksHit + fruitsHit;

View File

@ -6,7 +6,6 @@ using osu.Game.Rulesets.Catch.Difficulty.Preprocessing;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Skills;
using osuTK;
namespace osu.Game.Rulesets.Catch.Difficulty.Skills namespace osu.Game.Rulesets.Catch.Difficulty.Skills
{ {
@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills
if (lastPlayerPosition == null) if (lastPlayerPosition == null)
lastPlayerPosition = catchCurrent.LastNormalizedPosition; lastPlayerPosition = catchCurrent.LastNormalizedPosition;
float playerPosition = MathHelper.Clamp( float playerPosition = Math.Clamp(
lastPlayerPosition.Value, lastPlayerPosition.Value,
catchCurrent.NormalizedPosition - (normalized_hitobject_radius - absolute_player_positioning_error), catchCurrent.NormalizedPosition - (normalized_hitobject_radius - absolute_player_positioning_error),
catchCurrent.NormalizedPosition + (normalized_hitobject_radius - absolute_player_positioning_error) catchCurrent.NormalizedPosition + (normalized_hitobject_radius - absolute_player_positioning_error)

View File

@ -99,8 +99,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
const float small_pulp = large_pulp_3 / 2; const float small_pulp = large_pulp_3 / 2;
Vector2 positionAt(float angle, float distance) => new Vector2( Vector2 positionAt(float angle, float distance) => new Vector2(
distance * (float)Math.Sin(angle * Math.PI / 180), distance * MathF.Sin(angle * MathF.PI / 180),
distance * (float)Math.Cos(angle * Math.PI / 180)); distance * MathF.Cos(angle * MathF.PI / 180));
switch (representation) switch (representation)
{ {
@ -278,7 +278,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawable
{ {
base.Update(); base.Update();
border.Alpha = (float)MathHelper.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1); border.Alpha = (float)Math.Clamp((HitObject.StartTime - Time.Current) / 500, 0, 1);
} }
private Color4 colourForRepresentation(FruitVisualRepresentation representation) private Color4 colourForRepresentation(FruitVisualRepresentation representation)

View File

@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Catch.UI
fruit.Y -= RNG.NextSingle() * diff; fruit.Y -= RNG.NextSingle() * diff;
} }
fruit.X = MathHelper.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2); fruit.X = Math.Clamp(fruit.X, -CATCHER_SIZE / 2, CATCHER_SIZE / 2);
caughtFruit.Add(fruit); caughtFruit.Add(fruit);
} }
@ -378,7 +378,7 @@ namespace osu.Game.Rulesets.Catch.UI
double speed = BASE_SPEED * dashModifier * hyperDashModifier; double speed = BASE_SPEED * dashModifier * hyperDashModifier;
Scale = new Vector2(Math.Abs(Scale.X) * direction, Scale.Y); Scale = new Vector2(Math.Abs(Scale.X) * direction, Scale.Y);
X = (float)MathHelper.Clamp(X + direction * Clock.ElapsedFrameTime * speed, 0, 1); X = (float)Math.Clamp(X + direction * Clock.ElapsedFrameTime * speed, 0, 1);
// Correct overshooting. // Correct overshooting.
if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) ||

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>catch the fruit. to the beat.</Description> <Description>catch the fruit. to the beat.</Description>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Mania.Tests.Android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Mania.Tests.Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!mania Test" /> <application android:allowBackup="true" android:supportsRtl="true" android:label="osu!mania Test" />
</manifest> </manifest>

View File

@ -73,7 +73,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
{ {
BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty; BeatmapDifficulty difficulty = original.BeatmapInfo.BaseDifficulty;
int seed = (int)Math.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)Math.Round(difficulty.ApproachRate); int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate);
Random = new FastRandom(seed); Random = new FastRandom(seed);
return base.ConvertBeatmap(original); return base.ConvertBeatmap(original);

View File

@ -7,7 +7,6 @@ using JetBrains.Annotations;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.MathUtils; using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osuTK;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
@ -54,11 +53,11 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
if (allowSpecial && TotalColumns == 8) if (allowSpecial && TotalColumns == 8)
{ {
const float local_x_divisor = 512f / 7; const float local_x_divisor = 512f / 7;
return MathHelper.Clamp((int)Math.Floor(position / local_x_divisor), 0, 6) + 1; return Math.Clamp((int)MathF.Floor(position / local_x_divisor), 0, 6) + 1;
} }
float localXDivisor = 512f / TotalColumns; float localXDivisor = 512f / TotalColumns;
return MathHelper.Clamp((int)Math.Floor(position / localXDivisor), 0, TotalColumns - 1); return Math.Clamp((int)MathF.Floor(position / localXDivisor), 0, TotalColumns - 1);
} }
/// <summary> /// <summary>
@ -113,7 +112,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
drainTime = 10000; drainTime = 10000;
BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty; BeatmapDifficulty difficulty = OriginalBeatmap.BeatmapInfo.BaseDifficulty;
conversionDifficulty = ((difficulty.DrainRate + MathHelper.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15; conversionDifficulty = ((difficulty.DrainRate + Math.Clamp(difficulty.ApproachRate, 4, 7)) / 1.5 + (double)OriginalBeatmap.HitObjects.Count / drainTime * 9f) / 38f * 5f / 1.15;
conversionDifficulty = Math.Min(conversionDifficulty.Value, 12); conversionDifficulty = Math.Min(conversionDifficulty.Value, 12);
return conversionDifficulty.Value; return conversionDifficulty.Value;

View File

@ -1,6 +1,7 @@
// 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.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Timing; using osu.Framework.Timing;
@ -9,7 +10,6 @@ using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
namespace osu.Game.Rulesets.Mania.Edit namespace osu.Game.Rulesets.Mania.Edit
{ {
@ -119,7 +119,7 @@ namespace osu.Game.Rulesets.Mania.Edit
maxColumn = obj.Column; maxColumn = obj.Column;
} }
columnDelta = MathHelper.Clamp(columnDelta, -minColumn, composer.TotalColumns - 1 - maxColumn); columnDelta = Math.Clamp(columnDelta, -minColumn, composer.TotalColumns - 1 - maxColumn);
foreach (var obj in SelectedHitObjects.OfType<ManiaHitObject>()) foreach (var obj in SelectedHitObjects.OfType<ManiaHitObject>())
obj.Column += columnDelta; obj.Column += columnDelta;

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>smash the keys. to the beat.</Description> <Description>smash the keys. to the beat.</Description>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Osu.Tests.Android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Osu.Tests.Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!standard Test" /> <application android:allowBackup="true" android:supportsRtl="true" android:label="osu!standard Test" />
</manifest> </manifest>

View File

@ -16,9 +16,11 @@ using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Skinning; using osu.Game.Skinning;
using osu.Game.Storyboards;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
@ -75,14 +77,14 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin); protected override Player CreatePlayer(Ruleset ruleset) => new SkinProvidingPlayer(testUserSkin);
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) => new CustomSkinWorkingBeatmap(beatmap, Clock, audio, testBeatmapSkin); protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null) => new CustomSkinWorkingBeatmap(beatmap, storyboard, Clock, audio, testBeatmapSkin);
public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap public class CustomSkinWorkingBeatmap : ClockBackedTestWorkingBeatmap
{ {
private readonly ISkinSource skin; private readonly ISkinSource skin;
public CustomSkinWorkingBeatmap(IBeatmap beatmap, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin) public CustomSkinWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard, IFrameBasedClock frameBasedClock, AudioManager audio, ISkinSource skin)
: base(beatmap, frameBasedClock, audio) : base(beatmap, storyboard, frameBasedClock, audio)
{ {
this.skin = skin; this.skin = skin;
} }
@ -124,7 +126,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{ {
if (!enabled) return null; if (!enabled) return null;
return new SpriteText return new OsuSpriteText
{ {
Text = identifier, Text = identifier,
Font = OsuFont.Default.With(size: 30), Font = OsuFont.Default.With(size: 30),

View File

@ -15,6 +15,7 @@ using osu.Game.Tests.Visual;
using osuTK; using osuTK;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Storyboards;
using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap; using static osu.Game.Tests.Visual.OsuTestScene.ClockBackedTestWorkingBeatmap;
namespace osu.Game.Rulesets.Osu.Tests namespace osu.Game.Rulesets.Osu.Tests
@ -28,9 +29,9 @@ namespace osu.Game.Rulesets.Osu.Tests
protected override bool Autoplay => true; protected override bool Autoplay => true;
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ {
var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
track = (TrackVirtualManual)working.Track; track = (TrackVirtualManual)working.Track;
return working; return working;
} }

View File

@ -17,7 +17,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components
Origin = Anchor.Centre; Origin = Anchor.Centre;
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
CornerRadius = Size.X / 2; CornerRadius = Size.X / 2;
CornerExponent = 2;
InternalChild = new RingPiece(); InternalChild = new RingPiece();
} }

View File

@ -14,12 +14,13 @@ using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
public class PathControlPointPiece : BlueprintPiece<Slider> public class PathControlPointPiece : BlueprintPiece<Slider>
{ {
public Action<int> RequestSelection; public Action<int, MouseButtonEvent> RequestSelection;
public Action<Vector2[]> ControlPointsChanged; public Action<Vector2[]> ControlPointsChanged;
public readonly BindableBool IsSelected = new BindableBool(); public readonly BindableBool IsSelected = new BindableBool();
@ -129,10 +130,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
protected override bool OnMouseDown(MouseDownEvent e) protected override bool OnMouseDown(MouseDownEvent e)
{ {
if (RequestSelection != null) if (RequestSelection == null)
return false;
switch (e.Button)
{ {
RequestSelection.Invoke(Index); case MouseButton.Left:
RequestSelection.Invoke(Index, e);
return true; return true;
case MouseButton.Right:
if (!IsSelected.Value)
RequestSelection.Invoke(Index, e);
return false; // Allow context menu to show
} }
return false; return false;
@ -142,7 +152,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
protected override bool OnClick(ClickEvent e) => RequestSelection != null; protected override bool OnClick(ClickEvent e) => RequestSelection != null;
protected override bool OnDragStart(DragStartEvent e) => true; protected override bool OnDragStart(DragStartEvent e) => e.Button == MouseButton.Left;
protected override bool OnDrag(DragEvent e) protected override bool OnDrag(DragEvent e)
{ {

View File

@ -3,19 +3,25 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Humanizer;
using osu.Framework.Allocation; using osu.Framework.Allocation;
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.UserInterface;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose; using osu.Game.Screens.Edit.Compose;
using osuTK; using osuTK;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
{ {
public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler<PlatformAction> public class PathControlPointVisualiser : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IHasContextMenu
{ {
public Action<Vector2[]> ControlPointsChanged; public Action<Vector2[]> ControlPointsChanged;
@ -73,9 +79,22 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
return false; return false;
} }
private void selectPiece(int index) public bool OnPressed(PlatformAction action)
{ {
if (inputManager.CurrentState.Keyboard.ControlPressed) switch (action.ActionMethod)
{
case PlatformActionMethod.Delete:
return deleteSelected();
}
return false;
}
public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete;
private void selectPiece(int index, MouseButtonEvent e)
{
if (e.Button == MouseButton.Left && inputManager.CurrentState.Keyboard.ControlPressed)
Pieces[index].IsSelected.Toggle(); Pieces[index].IsSelected.Toggle();
else else
{ {
@ -84,11 +103,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
} }
} }
public bool OnPressed(PlatformAction action) private bool deleteSelected()
{ {
switch (action.ActionMethod)
{
case PlatformActionMethod.Delete:
var newControlPoints = new List<Vector2>(); var newControlPoints = new List<Vector2>();
foreach (var piece in Pieces) foreach (var piece in Pieces)
@ -121,13 +137,26 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
piece.IsSelected.Value = false; piece.IsSelected.Value = false;
ControlPointsChanged?.Invoke(newControlPoints.ToArray()); ControlPointsChanged?.Invoke(newControlPoints.ToArray());
return true; return true;
} }
return false; public MenuItem[] ContextMenuItems
} {
get
{
if (!Pieces.Any(p => p.IsHovered))
return null;
public bool OnReleased(PlatformAction action) => action.ActionMethod == PlatformActionMethod.Delete; int selectedPoints = Pieces.Count(p => p.IsSelected.Value);
if (selectedPoints == 0)
return null;
return new MenuItem[]
{
new OsuMenuItem($"Delete {"control point".ToQuantity(selectedPoints)}", MenuItemType.Destructive, () => deleteSelected())
};
}
}
} }
} }

View File

@ -1,6 +1,7 @@
// 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 osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -13,7 +14,6 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Scoring; using osu.Game.Scoring;
using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Mods namespace osu.Game.Rulesets.Osu.Mods
@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu.Mods
}; };
} }
private float calculateGap(float value) => MathHelper.Clamp(value, 0, target_clamp) * targetBreakMultiplier; private float calculateGap(float value) => Math.Clamp(value, 0, target_clamp) * targetBreakMultiplier;
// lagrange polinominal for (0,0) (0.6,0.4) (1,1) should make a good curve // lagrange polinominal for (0,0) (0.6,0.4) (1,1) should make a good curve
private static float applyAdjustmentCurve(float value) => 0.6f * value * value + 0.4f * value; private static float applyAdjustmentCurve(float value) => 0.6f * value * value + 0.4f * value;

View File

@ -1,6 +1,7 @@
// 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.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -55,7 +56,7 @@ namespace osu.Game.Rulesets.Osu.Mods
var destination = e.MousePosition; var destination = e.MousePosition;
FlashlightPosition = Interpolation.ValueAt( FlashlightPosition = Interpolation.ValueAt(
MathHelper.Clamp(Clock.ElapsedFrameTime, 0, follow_delay), position, destination, 0, follow_delay, Easing.Out); Math.Clamp(Clock.ElapsedFrameTime, 0, follow_delay), position, destination, 0, follow_delay, Easing.Out);
return base.OnMouseMove(e); return base.OnMouseMove(e);
} }

View File

@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods
float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2; float appearDistance = (float)(hitObject.TimePreempt - hitObject.TimeFadeIn) / 2;
Vector2 originalPosition = drawable.Position; Vector2 originalPosition = drawable.Position;
Vector2 appearOffset = new Vector2((float)Math.Cos(theta), (float)Math.Sin(theta)) * appearDistance; Vector2 appearOffset = new Vector2(MathF.Cos(theta), MathF.Sin(theta)) * appearDistance;
//the - 1 and + 1 prevents the hit objects to appear in the wrong position. //the - 1 and + 1 prevents the hit objects to appear in the wrong position.
double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1; double appearTime = hitObject.StartTime - hitObject.TimePreempt - 1;

View File

@ -25,11 +25,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
{ {
Origin = Anchor.Centre; Origin = Anchor.Centre;
Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.FollowPoint), _ => new Container Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.FollowPoint), _ => new CircularContainer
{ {
Masking = true, Masking = true,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
CornerRadius = width / 2,
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,

View File

@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
break; break;
} }
float aimRotation = MathHelper.RadiansToDegrees((float)Math.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X)); float aimRotation = MathHelper.RadiansToDegrees(MathF.Atan2(aimRotationVector.Y - Position.Y, aimRotationVector.X - Position.X));
while (Math.Abs(aimRotation - Rotation) > 180) while (Math.Abs(aimRotation - Rotation) > 180)
aimRotation += aimRotation < Rotation ? 360 : -360; aimRotation += aimRotation < Rotation ? 360 : -360;
@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
else else
{ {
// If we're already snaking, interpolate to smooth out sharp curves (linear sliders, mainly). // If we're already snaking, interpolate to smooth out sharp curves (linear sliders, mainly).
Rotation = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 100), Rotation, aimRotation, 0, 50, Easing.OutQuint); Rotation = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 100), Rotation, aimRotation, 0, 50, Easing.OutQuint);
} }
} }
} }

View File

@ -1,6 +1,7 @@
// 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 osuTK; using osuTK;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -165,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Tracking.Value = Ball.Tracking; Tracking.Value = Ball.Tracking;
double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
Ball.UpdateProgress(completionProgress); Ball.UpdateProgress(completionProgress);
Body.UpdateProgress(completionProgress); Body.UpdateProgress(completionProgress);

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
base.Update(); base.Update();
double completionProgress = MathHelper.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1); double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
//todo: we probably want to reconsider this before adding scoring, but it looks and feels nice. //todo: we probably want to reconsider this before adding scoring, but it looks and feels nice.
if (!IsHit) if (!IsHit)

View File

@ -1,6 +1,7 @@
// 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.Linq; using System.Linq;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -136,7 +137,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
positionBindable.BindTo(HitObject.PositionBindable); positionBindable.BindTo(HitObject.PositionBindable);
} }
public float Progress => MathHelper.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1); public float Progress => Math.Clamp(Disc.RotationAbsolute / 360 / Spinner.SpinsRequired, 0, 1);
protected override void CheckForResult(bool userTriggered, double timeOffset) protected override void CheckForResult(bool userTriggered, double timeOffset)
{ {

View File

@ -16,7 +16,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{ {
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2); Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
Masking = true; Masking = true;
CornerRadius = Size.X / 2; CornerRadius = Size.X / 2;
CornerExponent = 2;
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;

View File

@ -18,10 +18,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
InternalChild = new Container InternalChild = new CircularContainer
{ {
Masking = true, Masking = true,
CornerRadius = Size.X / 2,
BorderThickness = 10, BorderThickness = 10,
BorderColour = Color4.White, BorderColour = Color4.White,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
var spanProgress = slider.ProgressAt(completionProgress); var spanProgress = slider.ProgressAt(completionProgress);
double start = 0; double start = 0;
double end = SnakingIn.Value ? MathHelper.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / (slider.TimePreempt / 3), 0, 1) : 1; double end = SnakingIn.Value ? Math.Clamp((Time.Current - (slider.StartTime - slider.TimePreempt)) / (slider.TimePreempt / 3), 0, 1) : 1;
if (span >= slider.SpanCount() - 1) if (span >= slider.SpanCount() - 1)
{ {

View File

@ -20,9 +20,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
const int count = 18; const float count = 18;
for (int i = 0; i < count; i++) for (float i = 0; i < count; i++)
{ {
Add(new Container Add(new Container
{ {
@ -40,10 +40,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Size = new Vector2(60, 10), Size = new Vector2(60, 10),
Origin = Anchor.Centre, Origin = Anchor.Centre,
Position = new Vector2( Position = new Vector2(
0.5f + (float)Math.Sin((float)i / count * 2 * MathHelper.Pi) / 2 * 0.86f, 0.5f + MathF.Sin(i / count * 2 * MathF.PI) / 2 * 0.86f,
0.5f + (float)Math.Cos((float)i / count * 2 * MathHelper.Pi) / 2 * 0.86f 0.5f + MathF.Cos(i / count * 2 * MathF.PI) / 2 * 0.86f
), ),
Rotation = -(float)i / count * 360 + 90, Rotation = -i / count * 360 + 90,
Children = new[] Children = new[]
{ {
new Box new Box

View File

@ -185,14 +185,14 @@ namespace osu.Game.Rulesets.Osu.Replays
{ {
Vector2 spinCentreOffset = SPINNER_CENTRE - prevPos; Vector2 spinCentreOffset = SPINNER_CENTRE - prevPos;
float distFromCentre = spinCentreOffset.Length; float distFromCentre = spinCentreOffset.Length;
float distToTangentPoint = (float)Math.Sqrt(distFromCentre * distFromCentre - SPIN_RADIUS * SPIN_RADIUS); float distToTangentPoint = MathF.Sqrt(distFromCentre * distFromCentre - SPIN_RADIUS * SPIN_RADIUS);
if (distFromCentre > SPIN_RADIUS) if (distFromCentre > SPIN_RADIUS)
{ {
// Previous cursor position was outside spin circle, set startPosition to the tangent point. // Previous cursor position was outside spin circle, set startPosition to the tangent point.
// Angle between centre offset and tangent point offset. // Angle between centre offset and tangent point offset.
float angle = (float)Math.Asin(SPIN_RADIUS / distFromCentre); float angle = MathF.Asin(SPIN_RADIUS / distFromCentre);
if (angle > 0) if (angle > 0)
{ {
@ -204,8 +204,8 @@ namespace osu.Game.Rulesets.Osu.Replays
} }
// Rotate by angle so it's parallel to tangent line // Rotate by angle so it's parallel to tangent line
spinCentreOffset.X = spinCentreOffset.X * (float)Math.Cos(angle) - spinCentreOffset.Y * (float)Math.Sin(angle); spinCentreOffset.X = spinCentreOffset.X * MathF.Cos(angle) - spinCentreOffset.Y * MathF.Sin(angle);
spinCentreOffset.Y = spinCentreOffset.X * (float)Math.Sin(angle) + spinCentreOffset.Y * (float)Math.Cos(angle); spinCentreOffset.Y = spinCentreOffset.X * MathF.Sin(angle) + spinCentreOffset.Y * MathF.Cos(angle);
// Set length to distToTangentPoint // Set length to distToTangentPoint
spinCentreOffset.Normalize(); spinCentreOffset.Normalize();
@ -331,7 +331,7 @@ namespace osu.Game.Rulesets.Osu.Replays
Vector2 difference = startPosition - SPINNER_CENTRE; Vector2 difference = startPosition - SPINNER_CENTRE;
float radius = difference.Length; float radius = difference.Length;
float angle = radius == 0 ? 0 : (float)Math.Atan2(difference.Y, difference.X); float angle = radius == 0 ? 0 : MathF.Atan2(difference.Y, difference.X);
double t; double t;

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>click the circles. to the beat.</Description> <Description>click the circles. to the beat.</Description>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Taiko.Tests.Android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Rulesets.Taiko.Tests.Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!taiko Test" /> <application android:allowBackup="true" android:supportsRtl="true" android:label="osu!taiko Test" />
</manifest> </manifest>

View File

@ -1,12 +1,12 @@
// 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.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
else else
rollingHits--; rollingHits--;
rollingHits = MathHelper.Clamp(rollingHits, 0, rolling_hits_for_engaged_colour); rollingHits = Math.Clamp(rollingHits, 0, rolling_hits_for_engaged_colour);
Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1); Color4 newColour = Interpolation.ValueAt((float)rollingHits / rolling_hits_for_engaged_colour, colourIdle, colourEngaged, 0, 1);
MainPiece.FadeAccent(newColour, 100); MainPiece.FadeAccent(newColour, 100);

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces; using osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces;
using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
@ -179,7 +178,7 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
var completion = (float)numHits / HitObject.RequiredHits; var completion = (float)numHits / HitObject.RequiredHits;
expandingRing expandingRing
.FadeTo(expandingRing.Alpha + MathHelper.Clamp(completion / 16, 0.1f, 0.6f), 50) .FadeTo(expandingRing.Alpha + Math.Clamp(completion / 16, 0.1f, 0.6f), 50)
.Then() .Then()
.FadeTo(completion / 8, 2000, Easing.OutQuint); .FadeTo(completion / 8, 2000, Easing.OutQuint);

View File

@ -1,6 +1,7 @@
// 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 osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osuTK; using osuTK;
@ -22,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.UI
{ {
base.Update(); base.Update();
float aspectAdjust = MathHelper.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect; float aspectAdjust = Math.Clamp(Parent.ChildSize.X / Parent.ChildSize.Y, 0.4f, 4) / default_aspect;
Size = new Vector2(1, default_relative_height * aspectAdjust); Size = new Vector2(1, default_relative_height * aspectAdjust);
} }
} }

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>bash the drum. to the beat.</Description> <Description>bash the drum. to the beat.</Description>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Tests.Android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="osu.Game.Tests.Android" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
<application android:allowBackup="true" android:supportsRtl="true" android:label="osu!visual Test" /> <application android:allowBackup="true" android:supportsRtl="true" android:label="osu!visual Test" />
</manifest> </manifest>

View File

@ -3,6 +3,7 @@
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Audio; using osu.Game.Audio;
@ -13,7 +14,9 @@ namespace osu.Game.Tests.Visual.Components
{ {
public class TestScenePreviewTrackManager : OsuTestScene, IPreviewTrackOwner public class TestScenePreviewTrackManager : OsuTestScene, IPreviewTrackOwner
{ {
private readonly PreviewTrackManager trackManager = new TestPreviewTrackManager(); private readonly TestPreviewTrackManager trackManager = new TestPreviewTrackManager();
private AudioManager audio;
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
{ {
@ -24,8 +27,10 @@ namespace osu.Game.Tests.Visual.Components
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load(AudioManager audio)
{ {
this.audio = audio;
Add(trackManager); Add(trackManager);
} }
@ -108,6 +113,60 @@ namespace osu.Game.Tests.Visual.Components
AddAssert("track stopped", () => !track.IsRunning); AddAssert("track stopped", () => !track.IsRunning);
} }
/// <summary>
/// Ensures that <see cref="PreviewTrackManager.CurrentTrack"/> changes correctly.
/// </summary>
[Test]
public void TestCurrentTrackChanges()
{
PreviewTrack track = null;
TestTrackOwner owner = null;
AddStep("get track", () => Add(owner = new TestTrackOwner(track = getTrack())));
AddUntilStep("wait loaded", () => track.IsLoaded);
AddStep("start track", () => track.Start());
AddAssert("current is track", () => trackManager.CurrentTrack == track);
AddStep("pause manager updates", () => trackManager.AllowUpdate = false);
AddStep("stop any playing", () => trackManager.StopAnyPlaying(owner));
AddAssert("current not changed", () => trackManager.CurrentTrack == track);
AddStep("resume manager updates", () => trackManager.AllowUpdate = true);
AddAssert("current is null", () => trackManager.CurrentTrack == null);
}
/// <summary>
/// Ensures that <see cref="PreviewTrackManager"/> mutes game-wide audio tracks correctly.
/// </summary>
[TestCase(false)]
[TestCase(true)]
public void TestEnsureMutingCorrectly(bool stopAnyPlaying)
{
PreviewTrack track = null;
TestTrackOwner owner = null;
AddStep("ensure volume not zero", () =>
{
if (audio.Volume.Value == 0)
audio.Volume.Value = 1;
if (audio.VolumeTrack.Value == 0)
audio.VolumeTrack.Value = 1;
});
AddAssert("game not muted", () => audio.Tracks.AggregateVolume.Value != 0);
AddStep("get track", () => Add(owner = new TestTrackOwner(track = getTrack())));
AddUntilStep("wait loaded", () => track.IsLoaded);
AddStep("start track", () => track.Start());
AddAssert("game is muted", () => audio.Tracks.AggregateVolume.Value == 0);
if (stopAnyPlaying)
AddStep("stop any playing", () => trackManager.StopAnyPlaying(owner));
else
AddStep("stop track", () => track.Stop());
AddAssert("game not muted", () => audio.Tracks.AggregateVolume.Value != 0);
}
private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null); private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null);
private TestPreviewTrack getOwnedTrack() private TestPreviewTrack getOwnedTrack()
@ -144,8 +203,20 @@ namespace osu.Game.Tests.Visual.Components
public class TestPreviewTrackManager : PreviewTrackManager public class TestPreviewTrackManager : PreviewTrackManager
{ {
public bool AllowUpdate = true;
public new PreviewTrack CurrentTrack => base.CurrentTrack;
protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore); protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
public override bool UpdateSubTree()
{
if (!AllowUpdate)
return true;
return base.UpdateSubTree();
}
public class TestPreviewTrack : TrackManagerPreviewTrack public class TestPreviewTrack : TrackManagerPreviewTrack
{ {
private readonly ITrackStore trackManager; private readonly ITrackStore trackManager;

View File

@ -7,6 +7,7 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Storyboards;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
@ -29,9 +30,9 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); AddUntilStep("key counter reset", () => ((ScoreAccessiblePlayer)Player).HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
} }
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ {
var working = base.CreateWorkingBeatmap(beatmap); var working = base.CreateWorkingBeatmap(beatmap, storyboard);
track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track; track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track;

View File

@ -9,7 +9,7 @@ using osu.Game.Rulesets.Judgements;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Scoring;
@ -85,9 +85,9 @@ namespace osu.Game.Tests.Visual.Gameplay
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Children = new[] Children = new[]
{ {
new SpriteText { Text = $@"Great: {hitWindows?.WindowFor(HitResult.Great)}" }, new OsuSpriteText { Text = $@"Great: {hitWindows?.WindowFor(HitResult.Great)}" },
new SpriteText { Text = $@"Good: {hitWindows?.WindowFor(HitResult.Good)}" }, new OsuSpriteText { Text = $@"Good: {hitWindows?.WindowFor(HitResult.Good)}" },
new SpriteText { Text = $@"Meh: {hitWindows?.WindowFor(HitResult.Meh)}" }, new OsuSpriteText { Text = $@"Meh: {hitWindows?.WindowFor(HitResult.Meh)}" },
} }
}); });

View File

@ -17,6 +17,7 @@ using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Storyboards;
using osuTK; using osuTK;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
@ -35,9 +36,9 @@ namespace osu.Game.Tests.Visual.Gameplay
private Track track; private Track track;
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ {
var working = new ClockBackedTestWorkingBeatmap(beatmap, new FramedClock(new ManualClock { Rate = 1 }), audioManager); var working = new ClockBackedTestWorkingBeatmap(beatmap, storyboard, new FramedClock(new ManualClock { Rate = 1 }), audioManager);
track = working.Track; track = working.Track;
return working; return working;
} }

View File

@ -0,0 +1,113 @@
// 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.Diagnostics;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Play;
using osu.Game.Storyboards;
using osu.Game.Tests.Beatmaps;
using osuTK;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneLeadIn : RateAdjustedBeatmapTestScene
{
private LeadInPlayer player;
private const double lenience_ms = 10;
private const double first_hit_object = 2170;
[TestCase(1000, 0)]
[TestCase(2000, 0)]
[TestCase(3000, first_hit_object - 3000)]
[TestCase(10000, first_hit_object - 10000)]
public void TestLeadInProducesCorrectStartTime(double leadIn, double expectedStartTime)
{
loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo)
{
BeatmapInfo = { AudioLeadIn = leadIn }
});
AddAssert($"first frame is {expectedStartTime}", () =>
{
Debug.Assert(player.FirstFrameClockTime != null);
return Precision.AlmostEquals(player.FirstFrameClockTime.Value, expectedStartTime, lenience_ms);
});
}
[TestCase(1000, 0)]
[TestCase(0, 0)]
[TestCase(-1000, -1000)]
[TestCase(-10000, -10000)]
public void TestStoryboardProducesCorrectStartTime(double firstStoryboardEvent, double expectedStartTime)
{
var storyboard = new Storyboard();
var sprite = new StoryboardSprite("unknown", Anchor.TopLeft, Vector2.Zero);
sprite.TimelineGroup.Alpha.Add(Easing.None, firstStoryboardEvent, firstStoryboardEvent + 500, 0, 1);
storyboard.GetLayer("Background").Add(sprite);
loadPlayerWithBeatmap(new TestBeatmap(new OsuRuleset().RulesetInfo), storyboard);
AddAssert($"first frame is {expectedStartTime}", () =>
{
Debug.Assert(player.FirstFrameClockTime != null);
return Precision.AlmostEquals(player.FirstFrameClockTime.Value, expectedStartTime, lenience_ms);
});
}
private void loadPlayerWithBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{
AddStep("create player", () =>
{
Beatmap.Value = CreateWorkingBeatmap(beatmap, storyboard);
LoadScreen(player = new LeadInPlayer());
});
AddUntilStep("player loaded", () => player.IsLoaded && player.Alpha == 1);
}
private class LeadInPlayer : TestPlayer
{
public LeadInPlayer()
: base(false, false)
{
}
public double? FirstFrameClockTime;
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
public double GameplayStartTime => DrawableRuleset.GameplayStartTime;
public double FirstHitObjectTime => DrawableRuleset.Objects.First().StartTime;
public double GameplayClockTime => GameplayClockContainer.GameplayClock.CurrentTime;
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
if (!FirstFrameClockTime.HasValue)
{
FirstFrameClockTime = GameplayClockContainer.GameplayClock.CurrentTime;
AddInternal(new OsuSpriteText
{
Text = $"GameplayStartTime: {DrawableRuleset.GameplayStartTime} "
+ $"FirstHitObjectTime: {FirstHitObjectTime} "
+ $"LeadInTime: {Beatmap.Value.BeatmapInfo.AudioLeadIn} "
+ $"FirstFrameClockTime: {FirstFrameClockTime}"
});
}
}
}
}
}

View File

@ -6,6 +6,7 @@ using osu.Framework.Lists;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Storyboards;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
@ -42,9 +43,9 @@ namespace osu.Game.Tests.Visual.Gameplay
}); });
} }
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap) protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{ {
var working = base.CreateWorkingBeatmap(beatmap); var working = base.CreateWorkingBeatmap(beatmap, storyboard);
workingWeakReferences.Add(working); workingWeakReferences.Add(working);
return working; return working;
} }

View File

@ -4,8 +4,8 @@
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Mods;
using osu.Framework.Timing; using osu.Game.Rulesets.Osu;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osuTK; using osuTK;
using osuTK.Input; using osuTK.Input;
@ -18,25 +18,37 @@ namespace osu.Game.Tests.Visual.Gameplay
private SkipOverlay skip; private SkipOverlay skip;
private int requestCount; private int requestCount;
private double increment;
private GameplayClockContainer gameplayClockContainer;
private GameplayClock gameplayClock;
private const double skip_time = 6000;
[SetUp] [SetUp]
public void SetUp() => Schedule(() => public void SetUp() => Schedule(() =>
{ {
requestCount = 0; requestCount = 0;
Child = new Container increment = skip_time;
Child = gameplayClockContainer = new GameplayClockContainer(CreateWorkingBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)), new Mod[] { }, 0)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Clock = new FramedOffsetClock(Clock)
{
Offset = -Clock.CurrentTime,
},
Children = new Drawable[] Children = new Drawable[]
{ {
skip = new SkipOverlay(6000) skip = new SkipOverlay(skip_time)
{ {
RequestSeek = _ => requestCount++ RequestSkip = () =>
{
requestCount++;
gameplayClockContainer.Seek(gameplayClock.CurrentTime + increment);
}
} }
}, },
}; };
gameplayClockContainer.Start();
gameplayClock = gameplayClockContainer.GameplayClock;
}); });
[Test] [Test]
@ -64,19 +76,35 @@ namespace osu.Game.Tests.Visual.Gameplay
public void TestClickOnlyActuatesOnce() public void TestClickOnlyActuatesOnce()
{ {
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre)); AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddStep("click", () => InputManager.Click(MouseButton.Left)); AddStep("click", () =>
{
increment = skip_time - gameplayClock.CurrentTime - GameplayClockContainer.MINIMUM_SKIP_TIME / 2;
InputManager.Click(MouseButton.Left);
});
AddStep("click", () => InputManager.Click(MouseButton.Left)); AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left)); AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left)); AddStep("click", () => InputManager.Click(MouseButton.Left));
checkRequestCount(1); checkRequestCount(1);
} }
[Test]
public void TestClickOnlyActuatesMultipleTimes()
{
AddStep("set increment lower", () => increment = 3000);
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left));
AddStep("click", () => InputManager.Click(MouseButton.Left));
checkRequestCount(2);
}
[Test] [Test]
public void TestDoesntFadeOnMouseDown() public void TestDoesntFadeOnMouseDown()
{ {
AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre)); AddStep("move mouse", () => InputManager.MoveMouseTo(skip.ScreenSpaceDrawQuad.Centre));
AddStep("button down", () => InputManager.PressButton(MouseButton.Left)); AddStep("button down", () => InputManager.PressButton(MouseButton.Left));
AddUntilStep("wait for overlay disapper", () => !skip.IsAlive); AddUntilStep("wait for overlay disappear", () => !skip.IsPresent);
AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0); AddAssert("ensure button didn't disappear", () => skip.Children.First().Alpha > 0);
AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left)); AddStep("button up", () => InputManager.ReleaseButton(MouseButton.Left));
checkRequestCount(0); checkRequestCount(0);

View File

@ -42,6 +42,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(BeatmapAvailability), typeof(BeatmapAvailability),
typeof(BeatmapRulesetSelector), typeof(BeatmapRulesetSelector),
typeof(BeatmapRulesetTabItem), typeof(BeatmapRulesetTabItem),
typeof(NotSupporterPlaceholder)
}; };
protected override bool UseOnlineAPI => true; protected override bool UseOnlineAPI => true;

View File

@ -0,0 +1,78 @@
// 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 osu.Game.Overlays.BeatmapSet;
using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Taiko;
using osu.Game.Rulesets.Catch;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Bindables;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneLeaderboardModSelector : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(LeaderboardModSelector),
};
public TestSceneLeaderboardModSelector()
{
LeaderboardModSelector modSelector;
FillFlowContainer<SpriteText> selectedMods;
var ruleset = new Bindable<RulesetInfo>();
Add(selectedMods = new FillFlowContainer<SpriteText>
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft,
});
Add(modSelector = new LeaderboardModSelector
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Ruleset = { BindTarget = ruleset }
});
modSelector.SelectedMods.ItemsAdded += mods =>
{
mods.ForEach(mod => selectedMods.Add(new OsuSpriteText
{
Text = mod.Acronym,
}));
};
modSelector.SelectedMods.ItemsRemoved += mods =>
{
mods.ForEach(mod =>
{
foreach (var selected in selectedMods)
{
if (selected.Text == mod.Acronym)
{
selectedMods.Remove(selected);
break;
}
}
});
};
AddStep("osu ruleset", () => ruleset.Value = new OsuRuleset().RulesetInfo);
AddStep("mania ruleset", () => ruleset.Value = new ManiaRuleset().RulesetInfo);
AddStep("taiko ruleset", () => ruleset.Value = new TaikoRuleset().RulesetInfo);
AddStep("catch ruleset", () => ruleset.Value = new CatchRuleset().RulesetInfo);
AddStep("Deselect all", () => modSelector.DeselectAll());
AddStep("null ruleset", () => ruleset.Value = null);
}
}
}

View File

@ -0,0 +1,23 @@
// 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 osu.Game.Overlays;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneNewsOverlay : OsuTestScene
{
private NewsOverlay news;
protected override void LoadComplete()
{
base.LoadComplete();
Add(news = new NewsOverlay());
AddStep(@"Show", news.Show);
AddStep(@"Hide", news.Hide);
AddStep(@"Show front page", () => news.ShowFrontPage());
AddStep(@"Custom article", () => news.Current.Value = "Test Article 101");
}
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Rankings; using osu.Game.Overlays.Rankings;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;
@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.Online
Size = new Vector2(30, 20), Size = new Vector2(30, 20),
Country = countryA, Country = countryA,
}, },
text = new SpriteText text = new OsuSpriteText
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,

View File

@ -0,0 +1,36 @@
// 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 osu.Framework.Graphics;
using osu.Framework.Bindables;
using osu.Game.Overlays.Comments;
using osu.Framework.MathUtils;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneTotalCommentsCounter : OsuTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(TotalCommentsCounter),
};
public TestSceneTotalCommentsCounter()
{
var count = new BindableInt();
Add(new TotalCommentsCounter
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Current = { BindTarget = count }
});
AddStep(@"Set 100", () => count.Value = 100);
AddStep(@"Set 0", () => count.Value = 0);
AddStep(@"Set random", () => count.Value = RNG.Next(0, int.MaxValue));
}
}
}

View File

@ -11,7 +11,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania;
using osu.Game.Users; using osu.Game.Users;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Taiko; using osu.Game.Rulesets.Taiko;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
@ -94,11 +94,11 @@ namespace osu.Game.Tests.Visual.Online
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
new SpriteText new OsuSpriteText
{ {
Text = $@"Username: {user.NewValue?.Username}" Text = $@"Username: {user.NewValue?.Username}"
}, },
new SpriteText new OsuSpriteText
{ {
Text = $@"RankedScore: {user.NewValue?.Statistics.RankedScore}" Text = $@"RankedScore: {user.NewValue?.Statistics.RankedScore}"
}, },

View File

@ -57,23 +57,6 @@ namespace osu.Game.Tests.Visual.SongSelect
typeof(DrawableCarouselBeatmapSet), typeof(DrawableCarouselBeatmapSet),
}; };
private class TestSongSelect : PlaySongSelect
{
public Action StartRequested;
public new Bindable<RulesetInfo> Ruleset => base.Ruleset;
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
public new BeatmapCarousel Carousel => base.Carousel;
protected override bool OnStart()
{
StartRequested?.Invoke();
return base.OnStart();
}
}
private TestSongSelect songSelect; private TestSongSelect songSelect;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -101,6 +84,17 @@ namespace osu.Game.Tests.Visual.SongSelect
manager?.Delete(manager.GetAllUsableBeatmapSets()); manager?.Delete(manager.GetAllUsableBeatmapSets());
}); });
[Test]
public void TestSingleFilterOnEnter()
{
addRulesetImportStep(0);
addRulesetImportStep(0);
createSongSelect();
AddAssert("filter count is 1", () => songSelect.FilterCount == 1);
}
[Test] [Test]
public void TestAudioResuming() public void TestAudioResuming()
{ {
@ -373,5 +367,30 @@ namespace osu.Game.Tests.Visual.SongSelect
base.Dispose(isDisposing); base.Dispose(isDisposing);
rulesets?.Dispose(); rulesets?.Dispose();
} }
private class TestSongSelect : PlaySongSelect
{
public Action StartRequested;
public new Bindable<RulesetInfo> Ruleset => base.Ruleset;
public WorkingBeatmap CurrentBeatmap => Beatmap.Value;
public WorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap;
public new BeatmapCarousel Carousel => base.Carousel;
protected override bool OnStart()
{
StartRequested?.Invoke();
return base.OnStart();
}
public int FilterCount;
protected override void ApplyFilterToCarousel(FilterCriteria criteria)
{
FilterCount++;
base.ApplyFilterToCarousel(criteria);
}
}
} }
} }

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual
private IReadOnlyList<Type> requiredGameDependencies => new[] private IReadOnlyList<Type> requiredGameDependencies => new[]
{ {
typeof(OsuGame), typeof(OsuGame),
typeof(RavenLogger), typeof(SentryLogger),
typeof(OsuLogo), typeof(OsuLogo),
typeof(IdleTracker), typeof(IdleTracker),
typeof(OnScreenDisplay), typeof(OnScreenDisplay),

View File

@ -106,6 +106,7 @@ namespace osu.Game.Tournament.Components
Width = main_width, Width = main_width,
Height = TournamentBeatmapPanel.HEIGHT, Height = TournamentBeatmapPanel.HEIGHT,
CornerRadius = TournamentBeatmapPanel.HEIGHT / 2, CornerRadius = TournamentBeatmapPanel.HEIGHT / 2,
CornerExponent = 2,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box new Box
@ -126,6 +127,7 @@ namespace osu.Game.Tournament.Components
{ {
Masking = true, Masking = true,
CornerRadius = TournamentBeatmapPanel.HEIGHT / 2, CornerRadius = TournamentBeatmapPanel.HEIGHT / 2,
CornerExponent = 2,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -52,6 +52,7 @@ namespace osu.Game.Tournament.Components
currentMatch.BindTo(ladder.CurrentMatch); currentMatch.BindTo(ladder.CurrentMatch);
CornerRadius = HEIGHT / 2; CornerRadius = HEIGHT / 2;
CornerExponent = 2;
Masking = true; Masking = true;
AddRangeInternal(new Drawable[] AddRangeInternal(new Drawable[]

View File

@ -57,7 +57,7 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
groups.Add(g); groups.Add(g);
nextGroupName++; nextGroupName++;
if (i < (int)Math.Ceiling(numGroups / 2f)) if (i < (int)MathF.Ceiling(numGroups / 2f))
topGroups.Add(g); topGroups.Add(g);
else else
bottomGroups.Add(g); bottomGroups.Add(g);

View File

@ -100,7 +100,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
var diff = Math.Max(score1.Value, score2.Value) - Math.Min(score1.Value, score2.Value); var diff = Math.Max(score1.Value, score2.Value) - Math.Min(score1.Value, score2.Value);
losingBar.ResizeWidthTo(0, 400, Easing.OutQuint); losingBar.ResizeWidthTo(0, 400, Easing.OutQuint);
winningBar.ResizeWidthTo(Math.Min(0.4f, (float)Math.Pow(diff / 1500000f, 0.5) / 2), 400, Easing.OutQuint); winningBar.ResizeWidthTo(Math.Min(0.4f, MathF.Pow(diff / 1500000f, 0.5f) / 2), 400, Easing.OutQuint);
} }
protected override void Update() protected override void Update()

View File

@ -1,6 +1,7 @@
// 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 osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Primitives;
@ -32,7 +33,7 @@ namespace osu.Game.Tournament.Screens.Ladder
protected override bool OnScroll(ScrollEvent e) protected override bool OnScroll(ScrollEvent e)
{ {
var newScale = MathHelper.Clamp(scale + e.ScrollDelta.Y / 15 * scale, min_scale, max_scale); var newScale = Math.Clamp(scale + e.ScrollDelta.Y / 15 * scale, min_scale, max_scale);
this.MoveTo(target = target - e.MousePosition * (newScale - scale), 2000, Easing.OutQuint); this.MoveTo(target = target - e.MousePosition * (newScale - scale), 2000, Easing.OutQuint);
this.ScaleTo(scale = newScale, 2000, Easing.OutQuint); this.ScaleTo(scale = newScale, 2000, Easing.OutQuint);

View File

@ -12,13 +12,13 @@ using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Tournament.IPC; using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models; using osu.Game.Tournament.Models;
@ -104,7 +104,7 @@ namespace osu.Game.Tournament
Colour = Color4.Red, Colour = Color4.Red,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
new SpriteText new OsuSpriteText
{ {
Text = "Please make the window wider", Text = "Please make the window wider",
Font = OsuFont.Default.With(weight: "bold"), Font = OsuFont.Default.With(weight: "bold"),
@ -202,6 +202,7 @@ namespace osu.Game.Tournament
{ {
foreach (var p in t.Players) foreach (var p in t.Players)
{ {
if (p.Username == null || p.Statistics == null)
PopulateUser(p); PopulateUser(p);
addedInfo = true; addedInfo = true;
} }
@ -243,7 +244,6 @@ namespace osu.Game.Tournament
{ {
user.Username = res.Username; user.Username = res.Username;
user.Statistics = res.Statistics; user.Statistics = res.Statistics;
user.Username = res.Username;
user.Country = res.Country; user.Country = res.Country;
user.Cover = res.Cover; user.Cover = res.Cover;

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="Project"> <PropertyGroup Label="Project">
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>tools for tournaments.</Description> <Description>tools for tournaments.</Description>

View File

@ -22,7 +22,7 @@ namespace osu.Game.Audio
private AudioManager audio; private AudioManager audio;
private PreviewTrackStore trackStore; private PreviewTrackStore trackStore;
private TrackManagerPreviewTrack current; protected TrackManagerPreviewTrack CurrentTrack;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audio) private void load(AudioManager audio)
@ -48,17 +48,17 @@ namespace osu.Game.Audio
track.Started += () => Schedule(() => track.Started += () => Schedule(() =>
{ {
current?.Stop(); CurrentTrack?.Stop();
current = track; CurrentTrack = track;
audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable); audio.Tracks.AddAdjustment(AdjustableProperty.Volume, muteBindable);
}); });
track.Stopped += () => Schedule(() => track.Stopped += () => Schedule(() =>
{ {
if (current != track) if (CurrentTrack != track)
return; return;
current = null; CurrentTrack = null;
audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable); audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
}); });
@ -76,11 +76,11 @@ namespace osu.Game.Audio
/// <param name="source">The <see cref="IPreviewTrackOwner"/> which may be the owner of the <see cref="PreviewTrack"/>.</param> /// <param name="source">The <see cref="IPreviewTrackOwner"/> which may be the owner of the <see cref="PreviewTrack"/>.</param>
public void StopAnyPlaying(IPreviewTrackOwner source) public void StopAnyPlaying(IPreviewTrackOwner source)
{ {
if (current == null || current.Owner != source) if (CurrentTrack == null || CurrentTrack.Owner != source)
return; return;
current.Stop(); CurrentTrack.Stop();
current = null; // CurrentTrack should not be set to null here as it will result in incorrect handling in the track.Stopped callback above.
} }
/// <summary> /// <summary>

View File

@ -76,7 +76,7 @@ namespace osu.Game.Beatmaps
public string MD5Hash { get; set; } public string MD5Hash { get; set; }
// General // General
public int AudioLeadIn { get; set; } public double AudioLeadIn { get; set; }
public bool Countdown { get; set; } = true; public bool Countdown { get; set; } = true;
public float StackLeniency { get; set; } = 0.7f; public float StackLeniency { get; set; } = 0.7f;
public bool SpecialStyle { get; set; } public bool SpecialStyle { get; set; }

View File

@ -0,0 +1,11 @@
// 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.Configuration
{
public enum BackgroundSource
{
Skin,
Beatmap
}
}

View File

@ -117,6 +117,8 @@ namespace osu.Game.Configuration
Set(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f); Set(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f);
Set(OsuSetting.IntroSequence, IntroSequence.Triangles); Set(OsuSetting.IntroSequence, IntroSequence.Triangles);
Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
} }
public OsuConfigManager(Storage storage) public OsuConfigManager(Storage storage)
@ -186,6 +188,7 @@ namespace osu.Game.Configuration
UIScale, UIScale,
IntroSequence, IntroSequence,
UIHoldActivationDelay, UIHoldActivationDelay,
HitLighting HitLighting,
MenuBackgroundSource
} }
} }

View File

@ -0,0 +1,28 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
namespace osu.Game.Graphics.Backgrounds
{
public class BeatmapBackground : Background
{
public readonly WorkingBeatmap Beatmap;
private readonly string fallbackTextureName;
public BeatmapBackground(WorkingBeatmap beatmap, string fallbackTextureName = @"Backgrounds/bg1")
{
Beatmap = beatmap;
this.fallbackTextureName = fallbackTextureName;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Sprite.Texture = Beatmap?.Background ?? textures.Get(fallbackTextureName);
}
}
}

View File

@ -111,7 +111,7 @@ namespace osu.Game.Graphics.Backgrounds
float adjustedAlpha = HideAlphaDiscrepancies float adjustedAlpha = HideAlphaDiscrepancies
// Cubically scale alpha to make it drop off more sharply. // Cubically scale alpha to make it drop off more sharply.
? (float)Math.Pow(DrawColourInfo.Colour.AverageColour.Linear.A, 3) ? MathF.Pow(DrawColourInfo.Colour.AverageColour.Linear.A, 3)
: 1; : 1;
float elapsedSeconds = (float)Time.Elapsed / 1000; float elapsedSeconds = (float)Time.Elapsed / 1000;

View File

@ -1,6 +1,7 @@
// 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 osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input;
@ -48,7 +49,7 @@ namespace osu.Game.Graphics.Containers
if (!parallaxEnabled.Value) if (!parallaxEnabled.Value)
{ {
content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint); content.MoveTo(Vector2.Zero, firstUpdate ? 0 : 1000, Easing.OutQuint);
content.Scale = new Vector2(1 + System.Math.Abs(ParallaxAmount)); content.Scale = new Vector2(1 + Math.Abs(ParallaxAmount));
} }
}; };
} }
@ -71,10 +72,10 @@ namespace osu.Game.Graphics.Containers
const float parallax_duration = 100; const float parallax_duration = 100;
double elapsed = MathHelper.Clamp(Clock.ElapsedFrameTime, 0, parallax_duration); double elapsed = Math.Clamp(Clock.ElapsedFrameTime, 0, parallax_duration);
content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, parallax_duration, Easing.OutQuint); content.Position = Interpolation.ValueAt(elapsed, content.Position, offset, 0, parallax_duration, Easing.OutQuint);
content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + System.Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint); content.Scale = Interpolation.ValueAt(elapsed, content.Scale, new Vector2(1 + Math.Abs(ParallaxAmount)), 0, 1000, Easing.OutQuint);
} }
firstUpdate = false; firstUpdate = false;

View File

@ -1,12 +1,12 @@
// 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 osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using System;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
@ -29,7 +29,7 @@ namespace osu.Game.Graphics.UserInterface
get => length; get => length;
set set
{ {
length = MathHelper.Clamp(value, 0, 1); length = Math.Clamp(value, 0, 1);
updateBarLength(); updateBarLength();
} }
} }

View File

@ -175,9 +175,9 @@ namespace osu.Game.Graphics.UserInterface
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
leftBox.Scale = new Vector2(MathHelper.Clamp( leftBox.Scale = new Vector2(Math.Clamp(
Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1); Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
rightBox.Scale = new Vector2(MathHelper.Clamp( rightBox.Scale = new Vector2(Math.Clamp(
DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1); DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
} }

View File

@ -99,7 +99,7 @@ namespace osu.Game.Graphics.UserInterface
// dont bother calculating if the strip is invisible // dont bother calculating if the strip is invisible
if (strip.Colour.MaxAlpha > 0) if (strip.Colour.MaxAlpha > 0)
strip.Width = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth(), 0, 500, Easing.OutQuint); strip.Width = Interpolation.ValueAt(Math.Clamp(Clock.ElapsedFrameTime, 0, 1000), strip.Width, StripWidth(), 0, 500, Easing.OutQuint);
} }
public class OsuTabItem : TabItem<T>, IHasAccentColour public class OsuTabItem : TabItem<T>, IHasAccentColour

View File

@ -227,7 +227,7 @@ namespace osu.Game.Online.API
{ {
try try
{ {
return JObject.Parse(req.ResponseString).SelectToken("form_error", true).ToObject<RegistrationRequest.RegistrationRequestErrors>(); return JObject.Parse(req.GetResponseString()).SelectToken("form_error", true).ToObject<RegistrationRequest.RegistrationRequestErrors>();
} }
catch catch
{ {

View File

@ -113,7 +113,7 @@ namespace osu.Game.Online.API
cancelled = true; cancelled = true;
WebRequest?.Abort(); WebRequest?.Abort();
string responseString = WebRequest?.ResponseString; string responseString = WebRequest?.GetResponseString();
if (!string.IsNullOrEmpty(responseString)) if (!string.IsNullOrEmpty(responseString))
{ {
@ -150,7 +150,7 @@ namespace osu.Game.Online.API
private class DisplayableError private class DisplayableError
{ {
[JsonProperty("error")] [JsonProperty("error")]
public string ErrorMessage; public string ErrorMessage { get; set; }
} }
} }

View File

@ -10,13 +10,11 @@ namespace osu.Game.Online.API.Requests
{ {
private readonly BeatmapInfo beatmap; private readonly BeatmapInfo beatmap;
private string lookupString => beatmap.OnlineBeatmapID > 0 ? beatmap.OnlineBeatmapID.ToString() : $@"lookup?checksum={beatmap.MD5Hash}&filename={System.Uri.EscapeUriString(beatmap.Path)}";
public GetBeatmapRequest(BeatmapInfo beatmap) public GetBeatmapRequest(BeatmapInfo beatmap)
{ {
this.beatmap = beatmap; this.beatmap = beatmap;
} }
protected override string Target => $@"beatmaps/{lookupString}"; protected override string Target => $@"beatmaps/lookup?id={beatmap.OnlineBeatmapID}&checksum={beatmap.MD5Hash}&filename={System.Uri.EscapeUriString(beatmap.Path ?? string.Empty)}";
} }
} }

View File

@ -71,7 +71,7 @@ namespace osu.Game
[Cached] [Cached]
private readonly ScreenshotManager screenshotManager = new ScreenshotManager(); private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
protected RavenLogger RavenLogger; protected SentryLogger SentryLogger;
public virtual Storage GetStorageForStableInstall() => null; public virtual Storage GetStorageForStableInstall() => null;
@ -110,7 +110,7 @@ namespace osu.Game
forwardLoggedErrorsToNotifications(); forwardLoggedErrorsToNotifications();
RavenLogger = new RavenLogger(this); SentryLogger = new SentryLogger(this);
} }
private void updateBlockingOverlayFade() => private void updateBlockingOverlayFade() =>
@ -166,7 +166,7 @@ namespace osu.Game
dependencies.CacheAs(this); dependencies.CacheAs(this);
dependencies.Cache(RavenLogger); dependencies.Cache(SentryLogger);
dependencies.Cache(osuLogo = new OsuLogo { Alpha = 0 }); dependencies.Cache(osuLogo = new OsuLogo { Alpha = 0 });
@ -486,7 +486,7 @@ namespace osu.Game
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
RavenLogger.Dispose(); SentryLogger.Dispose();
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -0,0 +1,144 @@
// 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 osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Framework.Bindables;
using osu.Game.Rulesets;
using osuTK;
using osu.Game.Rulesets.UI;
using osu.Framework.Input.Events;
using osu.Game.Graphics.UserInterface;
using osuTK.Graphics;
using System;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
namespace osu.Game.Overlays.BeatmapSet
{
public class LeaderboardModSelector : CompositeDrawable
{
public readonly BindableList<Mod> SelectedMods = new BindableList<Mod>();
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private readonly FillFlowContainer<ModButton> modsContainer;
public LeaderboardModSelector()
{
AutoSizeAxes = Axes.Both;
InternalChild = modsContainer = new FillFlowContainer<ModButton>
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Full,
Spacing = new Vector2(4),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Ruleset.BindValueChanged(onRulesetChanged, true);
}
private void onRulesetChanged(ValueChangedEvent<RulesetInfo> ruleset)
{
SelectedMods.Clear();
modsContainer.Clear();
if (ruleset.NewValue == null)
return;
modsContainer.Add(new ModButton(new ModNoMod()));
modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllMods().Where(m => m.Ranked).Select(m => new ModButton(m)));
modsContainer.ForEach(button => button.OnSelectionChanged = selectionChanged);
}
protected override bool OnHover(HoverEvent e)
{
updateHighlighted();
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
updateHighlighted();
}
private void selectionChanged(Mod mod, bool selected)
{
if (selected)
SelectedMods.Add(mod);
else
SelectedMods.Remove(mod);
updateHighlighted();
}
private void updateHighlighted()
{
if (SelectedMods.Any())
return;
modsContainer.Children.Where(button => !button.IsHovered).ForEach(button => button.Highlighted.Value = !IsHovered);
}
public void DeselectAll() => modsContainer.ForEach(mod => mod.Selected.Value = false);
private class ModButton : ModIcon
{
private const int duration = 200;
public readonly BindableBool Highlighted = new BindableBool();
public Action<Mod, bool> OnSelectionChanged;
public ModButton(Mod mod)
: base(mod)
{
Scale = new Vector2(0.4f);
Add(new HoverClickSounds());
}
protected override void LoadComplete()
{
base.LoadComplete();
Highlighted.BindValueChanged(highlighted =>
{
if (Selected.Value)
return;
this.FadeColour(highlighted.NewValue ? Color4.White : Color4.DimGray, duration, Easing.OutQuint);
}, true);
Selected.BindValueChanged(selected =>
{
OnSelectionChanged?.Invoke(Mod, selected.NewValue);
Highlighted.TriggerChange();
}, true);
}
protected override bool OnClick(ClickEvent e)
{
Selected.Toggle();
return true;
}
protected override bool OnHover(HoverEvent e)
{
Highlighted.Value = true;
return false;
}
protected override void OnHoverLost(HoverLostEvent e)
{
base.OnHoverLost(e);
Highlighted.Value = false;
}
}
}
}

View File

@ -0,0 +1,46 @@
// 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 osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Screens.Select.Leaderboards;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class NoScoresPlaceholder : Container
{
private readonly SpriteText text;
public NoScoresPlaceholder()
{
AutoSizeAxes = Axes.Both;
Child = text = new OsuSpriteText();
}
public override void Show() => this.FadeIn(200, Easing.OutQuint);
public override void Hide() => this.FadeOut(200, Easing.OutQuint);
public void ShowWithScope(BeatmapLeaderboardScope scope)
{
Show();
switch (scope)
{
default:
text.Text = @"No scores have been set yet. Maybe you can be the first!";
break;
case BeatmapLeaderboardScope.Friend:
text.Text = @"None of your friends have set a score on this map yet.";
break;
case BeatmapLeaderboardScope.Country:
text.Text = @"No one from your country has set a score on this map yet.";
break;
}
}
}
}

View File

@ -0,0 +1,49 @@
// 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 osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
public class NotSupporterPlaceholder : Container
{
public NotSupporterPlaceholder()
{
LinkFlowContainer text;
AutoSizeAxes = Axes.Both;
Child = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new OsuSpriteText
{
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),
},
text = new LinkFlowContainer(t => t.Font = t.Font.With(size: 12))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
}
}
};
text.AddText("Click ");
text.AddLink("here", "/home/support");
text.AddText(" to see all the fancy features that you can get!");
}
}
}

View File

@ -13,6 +13,10 @@ using osu.Game.Online.API.Requests.Responses;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Framework.Bindables;
using osu.Game.Rulesets;
using osu.Game.Screens.Select.Leaderboards;
using osu.Game.Users;
namespace osu.Game.Overlays.BeatmapSet.Scores namespace osu.Game.Overlays.BeatmapSet.Scores
{ {
@ -20,32 +24,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{ {
private const int spacing = 15; private const int spacing = 15;
public readonly Bindable<BeatmapInfo> Beatmap = new Bindable<BeatmapInfo>();
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private readonly Bindable<BeatmapLeaderboardScope> scope = new Bindable<BeatmapLeaderboardScope>(BeatmapLeaderboardScope.Global);
private readonly Bindable<User> user = new Bindable<User>();
private readonly Box background; private readonly Box background;
private readonly ScoreTable scoreTable; private readonly ScoreTable scoreTable;
private readonly FillFlowContainer topScoresContainer; private readonly FillFlowContainer topScoresContainer;
private readonly LoadingAnimation loadingAnimation; private readonly DimmedLoadingLayer loading;
private readonly LeaderboardModSelector modSelector;
private readonly NoScoresPlaceholder noScoresPlaceholder;
private readonly FillFlowContainer content;
private readonly NotSupporterPlaceholder notSupporterPlaceholder;
[Resolved] [Resolved]
private IAPIProvider api { get; set; } private IAPIProvider api { get; set; }
private GetScoresRequest getScoresRequest; private GetScoresRequest getScoresRequest;
private BeatmapInfo beatmap;
public BeatmapInfo Beatmap
{
get => beatmap;
set
{
if (beatmap == value)
return;
beatmap = value;
getScores(beatmap);
}
}
protected APILegacyScores Scores protected APILegacyScores Scores
{ {
set set
@ -85,7 +82,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
new FillFlowContainer content = new FillFlowContainer
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
@ -93,9 +90,59 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Width = 0.95f, Width = 0.95f,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Spacing = new Vector2(0, spacing),
Margin = new MarginPadding { Vertical = spacing }, Margin = new MarginPadding { Vertical = spacing },
Children = new Drawable[] Children = new Drawable[]
{
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, spacing),
Children = new Drawable[]
{
new LeaderboardScopeSelector
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Current = { BindTarget = scope }
},
modSelector = new LeaderboardModSelector
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Ruleset = { BindTarget = ruleset }
}
}
},
new Container
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Vertical = spacing },
Children = new Drawable[]
{
noScoresPlaceholder = new NoScoresPlaceholder
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Alpha = 0,
AlwaysPresent = true,
Margin = new MarginPadding { Vertical = 10 }
},
notSupporterPlaceholder = new NotSupporterPlaceholder
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Alpha = 0,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, spacing),
Children = new Drawable[]
{ {
topScoresContainer = new FillFlowContainer topScoresContainer = new FillFlowContainer
{ {
@ -111,10 +158,19 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
} }
} }
}, },
loadingAnimation = new LoadingAnimation new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 10,
Child = loading = new DimmedLoadingLayer(iconScale: 0.8f)
{ {
Alpha = 0, Alpha = 0,
Margin = new MarginPadding(20), },
}
}
}
}
}, },
}; };
} }
@ -123,26 +179,88 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
background.Colour = colours.Gray2; background.Colour = colours.Gray2;
user.BindTo(api.LocalUser);
} }
private void getScores(BeatmapInfo beatmap) protected override void LoadComplete()
{
base.LoadComplete();
scope.BindValueChanged(_ => getScores());
ruleset.BindValueChanged(_ => getScores());
modSelector.SelectedMods.ItemsAdded += _ => getScores();
modSelector.SelectedMods.ItemsRemoved += _ => getScores();
Beatmap.BindValueChanged(onBeatmapChanged);
user.BindValueChanged(onUserChanged, true);
}
private void onBeatmapChanged(ValueChangedEvent<BeatmapInfo> beatmap)
{
var beatmapRuleset = beatmap.NewValue?.Ruleset;
if (ruleset.Value?.Equals(beatmapRuleset) ?? false)
{
modSelector.DeselectAll();
ruleset.TriggerChange();
}
else
ruleset.Value = beatmapRuleset;
scope.Value = BeatmapLeaderboardScope.Global;
}
private void onUserChanged(ValueChangedEvent<User> user)
{
if (modSelector.SelectedMods.Any())
modSelector.DeselectAll();
else
getScores();
modSelector.FadeTo(userIsSupporter ? 1 : 0);
}
private void getScores()
{ {
getScoresRequest?.Cancel(); getScoresRequest?.Cancel();
getScoresRequest = null; getScoresRequest = null;
noScoresPlaceholder.Hide();
if (Beatmap.Value?.OnlineBeatmapID.HasValue != true || Beatmap.Value.Status <= BeatmapSetOnlineStatus.Pending)
{
Scores = null; Scores = null;
content.Hide();
if (beatmap?.OnlineBeatmapID.HasValue != true || beatmap.Status <= BeatmapSetOnlineStatus.Pending)
return; return;
}
loadingAnimation.Show(); if (scope.Value != BeatmapLeaderboardScope.Global && !userIsSupporter)
getScoresRequest = new GetScoresRequest(beatmap, beatmap.Ruleset); {
Scores = null;
notSupporterPlaceholder.Show();
loading.Hide();
return;
}
notSupporterPlaceholder.Hide();
content.Show();
loading.Show();
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
getScoresRequest.Success += scores => getScoresRequest.Success += scores =>
{ {
loadingAnimation.Hide(); loading.Hide();
Scores = scores; Scores = scores;
if (!scores.Scores.Any())
noScoresPlaceholder.ShowWithScope(scope.Value);
}; };
api.Queue(getScoresRequest); api.Queue(getScoresRequest);
} }
private bool userIsSupporter => api.IsLoggedIn && api.LocalUser.Value.IsSupporter;
} }
} }

View File

@ -37,7 +37,6 @@ namespace osu.Game.Overlays
{ {
OsuScrollContainer scroll; OsuScrollContainer scroll;
Info info; Info info;
ScoresContainer scoreContainer;
Children = new Drawable[] Children = new Drawable[]
{ {
@ -59,7 +58,10 @@ namespace osu.Game.Overlays
{ {
Header = new Header(), Header = new Header(),
info = new Info(), info = new Info(),
scoreContainer = new ScoresContainer(), new ScoresContainer
{
Beatmap = { BindTarget = Header.Picker.Beatmap }
}
}, },
}, },
}, },
@ -71,7 +73,6 @@ namespace osu.Game.Overlays
Header.Picker.Beatmap.ValueChanged += b => Header.Picker.Beatmap.ValueChanged += b =>
{ {
info.Beatmap = b.NewValue; info.Beatmap = b.NewValue;
scoreContainer.Beatmap = b.NewValue;
scroll.ScrollToStart(); scroll.ScrollToStart();
}; };

View File

@ -16,6 +16,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Chat namespace osu.Game.Overlays.Chat
{ {
@ -202,7 +203,7 @@ namespace osu.Game.Overlays.Chat
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = lineHeight, Height = lineHeight,
}, },
text = new SpriteText text = new OsuSpriteText
{ {
Margin = new MarginPadding { Horizontal = 10 }, Margin = new MarginPadding { Horizontal = 10 },
Text = time.ToLocalTime().ToString("dd MMM yyyy"), Text = time.ToLocalTime().ToString("dd MMM yyyy"),

View File

@ -99,7 +99,7 @@ namespace osu.Game.Overlays.Chat.Tabs
private void tabCloseRequested(TabItem<Channel> tab) private void tabCloseRequested(TabItem<Channel> tab)
{ {
int totalTabs = TabContainer.Count - 1; // account for selectorTab int totalTabs = TabContainer.Count - 1; // account for selectorTab
int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs); int currentIndex = Math.Clamp(TabContainer.IndexOf(tab), 1, totalTabs);
if (tab == SelectedTab && totalTabs > 1) if (tab == SelectedTab && totalTabs > 1)
// Select the tab after tab-to-be-removed's index, or the tab before if current == last // Select the tab after tab-to-be-removed's index, or the tab before if current == last

View File

@ -10,6 +10,7 @@ using osu.Game.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osuTK; using osuTK;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Comments namespace osu.Game.Overlays.Comments
{ {
@ -48,7 +49,7 @@ namespace osu.Game.Overlays.Comments
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Children = new Drawable[] Children = new Drawable[]
{ {
new SpriteText new OsuSpriteText
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
@ -101,7 +102,7 @@ namespace osu.Game.Overlays.Comments
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Size = new Vector2(10), Size = new Vector2(10),
}, },
new SpriteText new OsuSpriteText
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics.Sprites;
using osuTK; using osuTK;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using Humanizer; using Humanizer;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Comments namespace osu.Game.Overlays.Comments
{ {
@ -31,7 +32,7 @@ namespace osu.Game.Overlays.Comments
Icon = FontAwesome.Solid.Trash, Icon = FontAwesome.Solid.Trash,
Size = new Vector2(14), Size = new Vector2(14),
}, },
countText = new SpriteText countText = new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
} }

View File

@ -14,6 +14,7 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using System.Linq; using System.Linq;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
namespace osu.Game.Overlays.Comments namespace osu.Game.Overlays.Comments
@ -100,6 +101,7 @@ namespace osu.Game.Overlays.Comments
Size = new Vector2(avatar_size), Size = new Vector2(avatar_size),
Masking = true, Masking = true,
CornerRadius = avatar_size / 2f, CornerRadius = avatar_size / 2f,
CornerExponent = 2,
}, },
} }
}, },
@ -122,7 +124,7 @@ namespace osu.Game.Overlays.Comments
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
}, },
new ParentUsername(comment), new ParentUsername(comment),
new SpriteText new OsuSpriteText
{ {
Alpha = comment.IsDeleted ? 1 : 0, Alpha = comment.IsDeleted ? 1 : 0,
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
@ -144,7 +146,7 @@ namespace osu.Game.Overlays.Comments
Colour = OsuColour.Gray(0.7f), Colour = OsuColour.Gray(0.7f),
Children = new Drawable[] Children = new Drawable[]
{ {
new SpriteText new OsuSpriteText
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
@ -195,7 +197,7 @@ namespace osu.Game.Overlays.Comments
if (comment.EditedAt.HasValue) if (comment.EditedAt.HasValue)
{ {
info.Add(new SpriteText info.Add(new OsuSpriteText
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
@ -290,7 +292,7 @@ namespace osu.Game.Overlays.Comments
this.count = count; this.count = count;
Alpha = count == 0 ? 0 : 1; Alpha = count == 0 ? 0 : 1;
Child = text = new SpriteText Child = text = new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold),
}; };
@ -323,7 +325,7 @@ namespace osu.Game.Overlays.Comments
Icon = FontAwesome.Solid.Reply, Icon = FontAwesome.Solid.Reply,
Size = new Vector2(14), Size = new Vector2(14),
}, },
new SpriteText new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true),
Text = parentComment?.User?.Username ?? parentComment?.LegacyName Text = parentComment?.User?.Username ?? parentComment?.LegacyName

View File

@ -11,6 +11,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics.Sprites;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Overlays.Comments namespace osu.Game.Overlays.Comments
@ -61,7 +62,7 @@ namespace osu.Game.Overlays.Comments
public TabButton(CommentsSortCriteria value) public TabButton(CommentsSortCriteria value)
{ {
Add(text = new SpriteText Add(text = new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: 14), Font = OsuFont.GetFont(size: 14),
Text = value.ToString() Text = value.ToString()

View File

@ -0,0 +1,81 @@
// 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 osu.Framework.Graphics.Containers;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Framework.Graphics.Sprites;
using osuTK;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Comments
{
public class TotalCommentsCounter : CompositeDrawable
{
public readonly BindableInt Current = new BindableInt();
private readonly SpriteText counter;
public TotalCommentsCounter()
{
RelativeSizeAxes = Axes.X;
Height = 50;
AddInternal(new FillFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Left = 50 },
Spacing = new Vector2(5, 0),
Children = new Drawable[]
{
new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = OsuFont.GetFont(size: 20, italics: true),
Text = @"Comments"
},
new CircularContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(0.05f)
},
counter = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Margin = new MarginPadding { Horizontal = 10, Vertical = 5 },
Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)
}
},
}
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
counter.Colour = colours.BlueLighter;
}
protected override void LoadComplete()
{
Current.BindValueChanged(value => counter.Text = value.NewValue.ToString("N0"), true);
base.LoadComplete();
}
}
}

View File

@ -110,7 +110,7 @@ namespace osu.Game.Overlays.Comments
} }
} }
}, },
sideNumber = new SpriteText sideNumber = new OsuSpriteText
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,

View File

@ -241,7 +241,7 @@ namespace osu.Game.Overlays.Dialog
protected override void PopOut() protected override void PopOut()
{ {
if (!actionInvoked) if (!actionInvoked && content.IsPresent)
// In the case a user did not choose an action before a hide was triggered, press the last button. // In the case a user did not choose an action before a hide was triggered, press the last button.
// This is presumed to always be a sane default "cancel" action. // This is presumed to always be a sane default "cancel" action.
buttonsContainer.Last().Click(); buttonsContainer.Last().Click();

View File

@ -96,7 +96,7 @@ namespace osu.Game.Overlays.Mods
} }
} }
foregroundIcon.Highlighted.Value = Selected; foregroundIcon.Selected.Value = Selected;
SelectionChanged?.Invoke(SelectedMod); SelectionChanged?.Invoke(SelectedMod);
return true; return true;

View File

@ -167,7 +167,7 @@ namespace osu.Game.Overlays.Mods
Spacing = new Vector2(50f, 0f), Spacing = new Vector2(50f, 0f),
Margin = new MarginPadding Margin = new MarginPadding
{ {
Top = 6, Top = 20,
}, },
AlwaysPresent = true AlwaysPresent = true
}, },

View File

@ -217,7 +217,7 @@ namespace osu.Game.Overlays.Music
break; break;
} }
dstIndex = MathHelper.Clamp(dstIndex, 0, items.Count - 1); dstIndex = Math.Clamp(dstIndex, 0, items.Count - 1);
if (srcIndex == dstIndex) if (srcIndex == dstIndex)
return; return;

View File

@ -0,0 +1,19 @@
// 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 osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Overlays.News
{
public abstract class NewsContent : FillFlowContainer
{
protected NewsContent()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Direction = FillDirection.Vertical;
Padding = new MarginPadding { Bottom = 100, Top = 20, Horizontal = 50 };
}
}
}

View File

@ -0,0 +1,109 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using System;
namespace osu.Game.Overlays.News
{
public class NewsHeader : OverlayHeader
{
private const string front_page_string = "Front Page";
private NewsHeaderTitle title;
public readonly Bindable<string> Current = new Bindable<string>(null);
public Action ShowFrontPage;
public NewsHeader()
{
TabControl.AddItem(front_page_string);
TabControl.Current.ValueChanged += e =>
{
if (e.NewValue == front_page_string)
ShowFrontPage?.Invoke();
};
Current.ValueChanged += showArticle;
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
TabControl.AccentColour = colour.Violet;
}
private void showArticle(ValueChangedEvent<string> e)
{
if (e.OldValue != null)
TabControl.RemoveItem(e.OldValue);
if (e.NewValue != null)
{
TabControl.AddItem(e.NewValue);
TabControl.Current.Value = e.NewValue;
title.IsReadingArticle = true;
}
else
{
TabControl.Current.Value = front_page_string;
title.IsReadingArticle = false;
}
}
protected override Drawable CreateBackground() => new NewsHeaderBackground();
protected override Drawable CreateContent() => new Container();
protected override ScreenTitle CreateTitle() => title = new NewsHeaderTitle();
private class NewsHeaderBackground : Sprite
{
public NewsHeaderBackground()
{
RelativeSizeAxes = Axes.Both;
FillMode = FillMode.Fill;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
Texture = textures.Get(@"Headers/news");
}
}
private class NewsHeaderTitle : ScreenTitle
{
private const string article_string = "Article";
public bool IsReadingArticle
{
set => Section = value ? article_string : front_page_string;
}
public NewsHeaderTitle()
{
Title = "News";
IsReadingArticle = false;
}
protected override Drawable CreateIcon() => new ScreenTitleTextureIcon(@"Icons/news");
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Violet;
}
}
}
}

View File

@ -0,0 +1,68 @@
// 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 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;
using osu.Game.Graphics.Containers;
using osu.Game.Overlays.News;
namespace osu.Game.Overlays
{
public class NewsOverlay : FullscreenOverlay
{
private NewsHeader header;
//ReSharper disable NotAccessedField.Local
private Container<NewsContent> content;
public readonly Bindable<string> Current = new Bindable<string>(null);
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.PurpleDarkAlternative
},
new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
header = new NewsHeader
{
ShowFrontPage = ShowFrontPage
},
content = new Container<NewsContent>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
}
},
},
},
};
header.Current.BindTo(Current);
Current.TriggerChange();
}
public void ShowFrontPage()
{
Current.Value = null;
Show();
}
}
}

View File

@ -390,7 +390,7 @@ namespace osu.Game.Overlays
Vector2 change = e.MousePosition - e.MouseDownPosition; Vector2 change = e.MousePosition - e.MouseDownPosition;
// Diminish the drag distance as we go further to simulate "rubber band" feeling. // Diminish the drag distance as we go further to simulate "rubber band" feeling.
change *= change.Length <= 0 ? 0 : (float)Math.Pow(change.Length, 0.7f) / change.Length; change *= change.Length <= 0 ? 0 : MathF.Pow(change.Length, 0.7f) / change.Length;
this.MoveTo(change); this.MoveTo(change);
return true; return true;

View File

@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Users; using osu.Game.Users;
using osuTK; using osuTK;
@ -63,7 +64,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
new Drawable[] new Drawable[]
{ {
hoverIcon = new HoverIconContainer(), hoverIcon = new HoverIconContainer(),
header = new SpriteText header = new OsuSpriteText
{ {
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,

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