Merge branch 'master' into first-run-behaviour-screen

This commit is contained in:
Bartłomiej Dach 2022-04-29 00:54:50 +02:00
commit 96f6c918a8
No known key found for this signature in database
GPG Key ID: BCECCD4FA41F6497
34 changed files with 192 additions and 215 deletions

View File

@ -52,7 +52,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.423.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2022.428.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Transitive Dependencies"> <ItemGroup Label="Transitive Dependencies">
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. --> <!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->

View File

@ -5,10 +5,10 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.MathUtils;
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 osu.Game.Utils;
namespace osu.Game.Rulesets.Catch.Beatmaps namespace osu.Game.Rulesets.Catch.Beatmaps
{ {
@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
public void ApplyPositionOffsets(IBeatmap beatmap) public void ApplyPositionOffsets(IBeatmap beatmap)
{ {
var rng = new FastRandom(RNG_SEED); var rng = new LegacyRandom(RNG_SEED);
float? lastPosition = null; float? lastPosition = null;
double lastStartTime = 0; double lastStartTime = 0;
@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
initialiseHyperDash(beatmap); initialiseHyperDash(beatmap);
} }
private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng) private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, LegacyRandom rng)
{ {
float offsetPosition = hitObject.OriginalX; float offsetPosition = hitObject.OriginalX;
double startTime = hitObject.StartTime; double startTime = hitObject.StartTime;
@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
/// <param name="position">The position which the offset should be applied to.</param> /// <param name="position">The position which the offset should be applied to.</param>
/// <param name="maxOffset">The maximum offset, cannot exceed 20px.</param> /// <param name="maxOffset">The maximum offset, cannot exceed 20px.</param>
/// <param name="rng">The random number generator.</param> /// <param name="rng">The random number generator.</param>
private static void applyRandomOffset(ref float position, double maxOffset, FastRandom rng) private static void applyRandomOffset(ref float position, double maxOffset, LegacyRandom rng)
{ {
bool right = rng.NextBool(); bool right = rng.NextBool();
float rand = Math.Min(20, (float)rng.Next(0, Math.Max(0, maxOffset))); float rand = Math.Min(20, (float)rng.Next(0, Math.Max(0, maxOffset)));

View File

@ -11,8 +11,8 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns; using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy; using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
using osu.Game.Utils;
using osuTK; using osuTK;
namespace osu.Game.Rulesets.Mania.Beatmaps namespace osu.Game.Rulesets.Mania.Beatmaps
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private readonly int originalTargetColumns; private readonly int originalTargetColumns;
// Internal for testing purposes // Internal for testing purposes
internal FastRandom Random { get; private set; } internal LegacyRandom Random { get; private set; }
private Pattern lastPattern = new Pattern(); private Pattern lastPattern = new Pattern();
@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
IBeatmapDifficultyInfo difficulty = original.Difficulty; IBeatmapDifficultyInfo difficulty = original.Difficulty;
int seed = (int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.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 LegacyRandom(seed);
return base.ConvertBeatmap(original, cancellationToken); return base.ConvertBeatmap(original, cancellationToken);
} }
@ -227,7 +227,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary> /// </summary>
private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator private class SpecificBeatmapPatternGenerator : Patterns.Legacy.PatternGenerator
{ {
public SpecificBeatmapPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) public SpecificBeatmapPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{ {
} }

View File

@ -8,12 +8,12 @@ using System.Linq;
using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Extensions.EnumExtensions;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Formats;
using osu.Game.Utils;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private PatternType convertType; private PatternType convertType;
public DistanceObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) public DistanceObjectPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{ {
convertType = PatternType.None; convertType = PatternType.None;

View File

@ -2,13 +2,13 @@
// 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.Collections.Generic; using System.Collections.Generic;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using System.Linq; using System.Linq;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Utils;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly int endTime; private readonly int endTime;
private readonly PatternType convertType; private readonly PatternType convertType;
public EndTimeObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) public EndTimeObjectPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{ {
endTime = (int)((HitObject as IHasDuration)?.EndTime ?? 0); endTime = (int)((HitObject as IHasDuration)?.EndTime ?? 0);

View File

@ -9,11 +9,11 @@ using osuTK;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Utils;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
private readonly PatternType convertType; private readonly PatternType convertType;
public HitObjectPatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density, public HitObjectPatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, double previousTime, Vector2 previousPosition, double density,
PatternType lastStair, IBeatmap originalBeatmap) PatternType lastStair, IBeatmap originalBeatmap)
: base(random, hitObject, beatmap, previousPattern, originalBeatmap) : base(random, hitObject, beatmap, previousPattern, originalBeatmap)
{ {

View File

@ -5,8 +5,8 @@ using System;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mania.MathUtils;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Utils;
namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
{ {
@ -23,14 +23,14 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
/// <summary> /// <summary>
/// The random number generator to use. /// The random number generator to use.
/// </summary> /// </summary>
protected readonly FastRandom Random; protected readonly LegacyRandom Random;
/// <summary> /// <summary>
/// The beatmap which <see cref="HitObject"/> is being converted from. /// The beatmap which <see cref="HitObject"/> is being converted from.
/// </summary> /// </summary>
protected readonly IBeatmap OriginalBeatmap; protected readonly IBeatmap OriginalBeatmap;
protected PatternGenerator(FastRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap) protected PatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(hitObject, beatmap, previousPattern) : base(hitObject, beatmap, previousPattern)
{ {
if (random == null) throw new ArgumentNullException(nameof(random)); if (random == null) throw new ArgumentNullException(nameof(random));

View File

@ -1,95 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
namespace osu.Game.Rulesets.Mania.MathUtils
{
/// <summary>
/// A PRNG specified in http://heliosphan.org/fastrandom.html.
/// </summary>
internal class FastRandom
{
private const double int_to_real = 1.0 / (int.MaxValue + 1.0);
private const uint int_mask = 0x7FFFFFFF;
private const uint y = 842502087;
private const uint z = 3579807591;
private const uint w = 273326509;
internal uint X { get; private set; }
internal uint Y { get; private set; } = y;
internal uint Z { get; private set; } = z;
internal uint W { get; private set; } = w;
public FastRandom(int seed)
{
X = (uint)seed;
}
public FastRandom()
: this(Environment.TickCount)
{
}
/// <summary>
/// Generates a random unsigned integer within the range [<see cref="uint.MinValue"/>, <see cref="uint.MaxValue"/>).
/// </summary>
/// <returns>The random value.</returns>
public uint NextUInt()
{
uint t = X ^ (X << 11);
X = Y;
Y = Z;
Z = W;
return W = W ^ (W >> 19) ^ t ^ (t >> 8);
}
/// <summary>
/// Generates a random integer value within the range [0, <see cref="int.MaxValue"/>).
/// </summary>
/// <returns>The random value.</returns>
public int Next() => (int)(int_mask & NextUInt());
/// <summary>
/// Generates a random integer value within the range [0, <paramref name="upperBound"/>).
/// </summary>
/// <param name="upperBound">The upper bound.</param>
/// <returns>The random value.</returns>
public int Next(int upperBound) => (int)(NextDouble() * upperBound);
/// <summary>
/// Generates a random integer value within the range [<paramref name="lowerBound"/>, <paramref name="upperBound"/>).
/// </summary>
/// <param name="lowerBound">The lower bound of the range.</param>
/// <param name="upperBound">The upper bound of the range.</param>
/// <returns>The random value.</returns>
public int Next(int lowerBound, int upperBound) => (int)(lowerBound + NextDouble() * (upperBound - lowerBound));
/// <summary>
/// Generates a random double value within the range [0, 1).
/// </summary>
/// <returns>The random value.</returns>
public double NextDouble() => int_to_real * Next();
private uint bitBuffer;
private int bitIndex = 32;
/// <summary>
/// Generates a reandom boolean value. Cached such that a random value is only generated once in every 32 calls.
/// </summary>
/// <returns>The random value.</returns>
public bool NextBool()
{
if (bitIndex == 32)
{
bitBuffer = NextUInt();
bitIndex = 1;
return (bitBuffer & 1) == 1;
}
bitIndex++;
return ((bitBuffer >>= 1) & 1) == 1;
}
}
}

View File

@ -9,6 +9,10 @@ namespace osu.Game.Rulesets.Osu.Mods
{ {
public class OsuModSuddenDeath : ModSuddenDeath public class OsuModSuddenDeath : ModSuddenDeath
{ {
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray(); public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[]
{
typeof(OsuModAutopilot),
typeof(OsuModTarget),
}).ToArray();
} }
} }

View File

@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override string Description => @"Practice keeping up with the beat of the song."; public override string Description => @"Practice keeping up with the beat of the song.";
public override double ScoreMultiplier => 1; public override double ScoreMultiplier => 1;
public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles) }; public override Type[] IncompatibleMods => new[] { typeof(IRequiresApproachCircles), typeof(OsuModSuddenDeath) };
[SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))] [SettingSource("Seed", "Use a custom seed instead of a random one", SettingControlType = typeof(SettingsNumberBox))]
public Bindable<int?> Seed { get; } = new Bindable<int?> public Bindable<int?> Seed { get; } = new Bindable<int?>

View File

@ -160,6 +160,40 @@ namespace osu.Game.Tests.Gameplay
assertHealthNotEqualTo(1); assertHealthNotEqualTo(1);
} }
[Test]
public void TestFailConditions()
{
var beatmap = createBeatmap(0, 1000);
createProcessor(beatmap);
AddStep("setup fail conditions", () => processor.FailConditions += ((_, result) => result.Type == HitResult.Miss));
AddStep("apply perfect hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Perfect }));
AddAssert("not failed", () => !processor.HasFailed);
AddStep("apply miss hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Miss }));
AddAssert("failed", () => processor.HasFailed);
}
[TestCase(HitResult.Miss)]
[TestCase(HitResult.Meh)]
public void TestMultipleFailConditions(HitResult resultApplied)
{
var beatmap = createBeatmap(0, 1000);
createProcessor(beatmap);
AddStep("setup multiple fail conditions", () =>
{
processor.FailConditions += ((_, result) => result.Type == HitResult.Miss);
processor.FailConditions += ((_, result) => result.Type == HitResult.Meh);
});
AddStep("apply perfect hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = HitResult.Perfect }));
AddAssert("not failed", () => !processor.HasFailed);
AddStep($"apply {resultApplied.ToString().ToLower()} hit result", () => processor.ApplyResult(new JudgementResult(beatmap.HitObjects[0], new Judgement()) { Type = resultApplied }));
AddAssert("failed", () => processor.HasFailed);
}
[Test] [Test]
public void TestBonusObjectsExcludedFromDrain() public void TestBonusObjectsExcludedFromDrain()
{ {

View File

@ -1,13 +1,18 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Overlays;
using osu.Game.Overlays.FirstRunSetup; using osu.Game.Overlays.FirstRunSetup;
namespace osu.Game.Tests.Visual.UserInterface namespace osu.Game.Tests.Visual.UserInterface
{ {
public class TestSceneFirstRunScreenUIScale : OsuManualInputManagerTestScene public class TestSceneFirstRunScreenUIScale : OsuManualInputManagerTestScene
{ {
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
public TestSceneFirstRunScreenUIScale() public TestSceneFirstRunScreenUIScale()
{ {
AddStep("load screen", () => AddStep("load screen", () =>

View File

@ -28,11 +28,6 @@ namespace osu.Game.Beatmaps.Drawables
}, },
downloadTracker = new BeatmapDownloadTracker(beatmapSet), downloadTracker = new BeatmapDownloadTracker(beatmapSet),
}; };
AddInternal(progressBar = new ProgressBar(false)
{
Height = 0,
Alpha = 0,
});
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;

View File

@ -3,6 +3,7 @@
using System; using System;
using Humanizer; using Humanizer;
using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
@ -42,12 +43,12 @@ namespace osu.Game.Extensions
public static LocalisableString ToFormattedDuration(this TimeSpan timeSpan) public static LocalisableString ToFormattedDuration(this TimeSpan timeSpan)
{ {
if (timeSpan.TotalDays >= 1) if (timeSpan.TotalDays >= 1)
return new LocalisableFormattableString(timeSpan, @"dd\:hh\:mm\:ss"); return timeSpan.ToLocalisableString(@"dd\:hh\:mm\:ss");
if (timeSpan.TotalHours >= 1) if (timeSpan.TotalHours >= 1)
return new LocalisableFormattableString(timeSpan, @"hh\:mm\:ss"); return timeSpan.ToLocalisableString(@"hh\:mm\:ss");
return new LocalisableFormattableString(timeSpan, @"mm\:ss"); return timeSpan.ToLocalisableString(@"mm\:ss");
} }
/// <summary> /// <summary>

View File

@ -12,7 +12,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
@ -131,22 +130,7 @@ namespace osu.Game.Graphics.UserInterface
BackgroundColourSelected = SelectionColour BackgroundColourSelected = SelectionColour
}; };
protected override ScrollContainer<Drawable> CreateScrollContainer(Direction direction) => new DropdownScrollContainer(direction); protected override ScrollContainer<Drawable> CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction);
// Hotfix for https://github.com/ppy/osu/issues/17961
public class DropdownScrollContainer : OsuScrollContainer
{
public DropdownScrollContainer(Direction direction)
: base(direction)
{
}
protected override bool OnMouseDown(MouseDownEvent e)
{
base.OnMouseDown(e);
return true;
}
}
#region DrawableOsuDropdownMenuItem #region DrawableOsuDropdownMenuItem

View File

@ -9,7 +9,6 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -82,22 +81,7 @@ namespace osu.Game.Graphics.UserInterface
return new DrawableOsuMenuItem(item); return new DrawableOsuMenuItem(item);
} }
protected override ScrollContainer<Drawable> CreateScrollContainer(Direction direction) => new OsuMenuScrollContainer(direction); protected override ScrollContainer<Drawable> CreateScrollContainer(Direction direction) => new OsuScrollContainer(direction);
// Hotfix for https://github.com/ppy/osu/issues/17961
public class OsuMenuScrollContainer : OsuScrollContainer
{
public OsuMenuScrollContainer(Direction direction)
: base(direction)
{
}
protected override bool OnMouseDown(MouseDownEvent e)
{
base.OnMouseDown(e);
return true;
}
}
protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical) protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical)
{ {

View File

@ -4,6 +4,8 @@
#nullable enable #nullable enable
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -31,6 +33,9 @@ namespace osu.Game.Graphics.UserInterfaceV2
private Color4 enabledColour; private Color4 enabledColour;
private Color4 disabledColour; private Color4 disabledColour;
private Sample? sampleChecked;
private Sample? sampleUnchecked;
public SwitchButton() public SwitchButton()
{ {
Size = new Vector2(45, 20); Size = new Vector2(45, 20);
@ -70,13 +75,16 @@ namespace osu.Game.Graphics.UserInterfaceV2
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(OverlayColourProvider? colourProvider, OsuColour colours) private void load(OverlayColourProvider? colourProvider, OsuColour colours, AudioManager audio)
{ {
enabledColour = colourProvider?.Highlight1 ?? colours.BlueDark; enabledColour = colourProvider?.Highlight1 ?? colours.BlueDark;
disabledColour = colourProvider?.Background3 ?? colours.Gray3; disabledColour = colourProvider?.Background3 ?? colours.Gray3;
switchContainer.Colour = enabledColour; switchContainer.Colour = enabledColour;
fill.Colour = disabledColour; fill.Colour = disabledColour;
sampleChecked = audio.Samples.Get(@"UI/check-on");
sampleUnchecked = audio.Samples.Get(@"UI/check-off");
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -107,6 +115,16 @@ namespace osu.Game.Graphics.UserInterfaceV2
base.OnHoverLost(e); base.OnHoverLost(e);
} }
protected override void OnUserChange(bool value)
{
base.OnUserChange(value);
if (value)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
}
private void updateBorder() private void updateBorder()
{ {
circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0)); circularContainer.TransformBorderTo((Current.Value ? enabledColour : disabledColour).Lighten(IsHovered ? 0.3f : 0));

View File

@ -72,7 +72,8 @@ namespace osu.Game.Overlays.BeatmapListing
Size = new Vector2(12), Size = new Vector2(12),
Icon = getIconForCardSize(Value) Icon = getIconForCardSize(Value)
} }
} },
new HoverClickSounds(HoverSampleSet.TabSelect)
}; };
} }

View File

@ -119,7 +119,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x"); maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x");
ppColumn.Alpha = value.BeatmapInfo.Status.GrantsPerformancePoints() ? 1 : 0; ppColumn.Alpha = value.BeatmapInfo.Status.GrantsPerformancePoints() ? 1 : 0;
ppColumn.Text = value.PP?.ToLocalisableString(@"N0"); ppColumn.Text = value.PP?.ToLocalisableString(@"N0") ?? default(LocalisableString);
statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn); statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn);
modsColumn.Mods = value.Mods; modsColumn.Mods = value.Mods;

View File

@ -1,10 +1,14 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK; using osuTK;
namespace osu.Game.Overlays.FirstRunSetup namespace osu.Game.Overlays.FirstRunSetup
@ -15,20 +19,34 @@ namespace osu.Game.Overlays.FirstRunSetup
protected FillFlowContainer Content { get; private set; } protected FillFlowContainer Content { get; private set; }
protected FirstRunSetupScreen() [BackgroundDependencyLoader]
private void load(OverlayColourProvider overlayColourProvider)
{ {
const float header_size = 40;
const float spacing = 20;
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new OsuScrollContainer(Direction.Vertical) new OsuScrollContainer(Direction.Vertical)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
ScrollbarOverlapsContent = false, ScrollbarOverlapsContent = false,
Child = Content = new FillFlowContainer Children = new Drawable[]
{ {
Spacing = new Vector2(20), new OsuSpriteText
RelativeSizeAxes = Axes.X, {
AutoSizeAxes = Axes.Y, Text = this.GetLocalisableDescription(),
Direction = FillDirection.Vertical, Font = OsuFont.Default.With(size: header_size),
Colour = overlayColourProvider.Light1,
},
Content = new FillFlowContainer
{
Y = header_size + spacing,
Spacing = new Vector2(spacing),
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
}
}, },
} }
}; };

View File

@ -5,6 +5,7 @@ using System.Linq;
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.Localisation;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
@ -15,6 +16,7 @@ using osu.Game.Overlays.Settings.Sections;
namespace osu.Game.Overlays.FirstRunSetup namespace osu.Game.Overlays.FirstRunSetup
{ {
[LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.Behaviour))]
public class ScreenBehaviour : FirstRunSetupScreen public class ScreenBehaviour : FirstRunSetupScreen
{ {
private SearchContainer<SettingsSection> searchContainer; private SearchContainer<SettingsSection> searchContainer;

View File

@ -27,6 +27,7 @@ using osuTK;
namespace osu.Game.Overlays.FirstRunSetup namespace osu.Game.Overlays.FirstRunSetup
{ {
[LocalisableDescription(typeof(GraphicsSettingsStrings), nameof(GraphicsSettingsStrings.UIScaling))]
public class ScreenUIScale : FirstRunSetupScreen public class ScreenUIScale : FirstRunSetupScreen
{ {
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -1,16 +1,20 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Localisation; using osu.Game.Localisation;
namespace osu.Game.Overlays.FirstRunSetup namespace osu.Game.Overlays.FirstRunSetup
{ {
[LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.WelcomeTitle))]
public class ScreenWelcome : FirstRunSetupScreen public class ScreenWelcome : FirstRunSetupScreen
{ {
public ScreenWelcome() [BackgroundDependencyLoader]
private void load()
{ {
Content.Children = new Drawable[] Content.Children = new Drawable[]
{ {

View File

@ -7,6 +7,7 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions;
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;
@ -56,11 +57,11 @@ namespace osu.Game.Overlays
/// </summary> /// </summary>
public FirstRunSetupScreen? CurrentScreen => (FirstRunSetupScreen?)stack?.CurrentScreen; public FirstRunSetupScreen? CurrentScreen => (FirstRunSetupScreen?)stack?.CurrentScreen;
private readonly FirstRunStep[] steps = private readonly Type[] steps =
{ {
new FirstRunStep(typeof(ScreenWelcome), FirstRunSetupOverlayStrings.WelcomeTitle), typeof(ScreenWelcome),
new FirstRunStep(typeof(ScreenUIScale), GraphicsSettingsStrings.UIScaling), typeof(ScreenUIScale),
new FirstRunStep(typeof(ScreenBehaviour), FirstRunSetupOverlayStrings.Behaviour), typeof(ScreenBehaviour),
}; };
private Container stackContainer = null!; private Container stackContainer = null!;
@ -287,7 +288,7 @@ namespace osu.Game.Overlays
if (currentStepIndex < steps.Length) if (currentStepIndex < steps.Length)
{ {
stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value].ScreenType)); stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value]));
} }
else else
{ {
@ -318,23 +319,11 @@ namespace osu.Game.Overlays
} }
else else
{ {
BackButton.Text = new TranslatableString(@"_", @"{0} ({1})", CommonStrings.Back, steps[currentStepIndex.Value - 1].Description); BackButton.Text = LocalisableString.Interpolate($@"{CommonStrings.Back} ({steps[currentStepIndex.Value - 1].GetLocalisableDescription()})");
NextButton.Text = isLastStep NextButton.Text = isLastStep
? CommonStrings.Finish ? CommonStrings.Finish
: new TranslatableString(@"_", @"{0} ({1})", CommonStrings.Next, steps[currentStepIndex.Value + 1].Description); : LocalisableString.Interpolate($@"{CommonStrings.Next} ({steps[currentStepIndex.Value + 1].GetLocalisableDescription()})");
}
}
private class FirstRunStep
{
public readonly Type ScreenType;
public readonly LocalisableString Description;
public FirstRunStep(Type screenType, LocalisableString description)
{
ScreenType = screenType;
Description = description;
} }
} }
} }

View File

@ -441,7 +441,7 @@ namespace osu.Game.Overlays.Mods
protected override bool OnKeyDown(KeyDownEvent e) protected override bool OnKeyDown(KeyDownEvent e)
{ {
if (e.ControlPressed || e.AltPressed) return false; if (e.ControlPressed || e.AltPressed || e.SuperPressed) return false;
if (toggleKeys == null) return false; if (toggleKeys == null) return false;
int index = Array.IndexOf(toggleKeys, e.Key); int index = Array.IndexOf(toggleKeys, e.Key);

View File

@ -149,7 +149,7 @@ namespace osu.Game.Overlays
} }
}); });
AddInternal(new HoverClickSounds()); AddInternal(new HoverClickSounds(HoverSampleSet.TabSelect));
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
private void updateProgress(APIUser user) private void updateProgress(APIUser user)
{ {
levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0; levelProgressBar.Length = user?.Statistics?.Level.Progress / 100f ?? 0;
levelProgressText.Text = user?.Statistics?.Level.Progress.ToLocalisableString("0'%'"); levelProgressText.Text = user?.Statistics?.Level.Progress.ToLocalisableString("0'%'") ?? default(LocalisableString);
} }
} }
} }

View File

@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Rankings
startDateColumn.Value = dateToString(response.Spotlight.StartDate); startDateColumn.Value = dateToString(response.Spotlight.StartDate);
endDateColumn.Value = dateToString(response.Spotlight.EndDate); endDateColumn.Value = dateToString(response.Spotlight.EndDate);
mapCountColumn.Value = response.BeatmapSets.Count.ToLocalisableString(@"N0"); mapCountColumn.Value = response.BeatmapSets.Count.ToLocalisableString(@"N0");
participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString(@"N0"); participantsColumn.Value = response.Spotlight.Participants?.ToLocalisableString(@"N0") ?? default(LocalisableString);
} }
private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString(@"yyyy-MM-dd"); private LocalisableString dateToString(DateTimeOffset date) => date.ToLocalisableString(@"yyyy-MM-dd");

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Game.Resources.Localisation.Web; using osu.Game.Resources.Localisation.Web;
using osu.Game.Users; using osu.Game.Users;
@ -24,7 +25,7 @@ namespace osu.Game.Overlays.Rankings.Tables
protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[]
{ {
new RowText { Text = item.PP?.ToLocalisableString(@"N0"), } new RowText { Text = item.PP?.ToLocalisableString(@"N0") ?? default(LocalisableString), }
}; };
} }
} }

View File

@ -43,11 +43,11 @@ namespace osu.Game.Rulesets.Scoring
Health.Value += GetHealthIncreaseFor(result); Health.Value += GetHealthIncreaseFor(result);
if (!DefaultFailCondition && FailConditions?.Invoke(this, result) != true) if (meetsAnyFailCondition(result))
return; {
if (Failed?.Invoke() != false)
if (Failed?.Invoke() != false) HasFailed = true;
HasFailed = true; }
} }
protected override void RevertResultInternal(JudgementResult result) protected override void RevertResultInternal(JudgementResult result)
@ -69,6 +69,28 @@ namespace osu.Game.Rulesets.Scoring
/// </summary> /// </summary>
protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value); protected virtual bool DefaultFailCondition => Precision.AlmostBigger(Health.MinValue, Health.Value);
/// <summary>
/// Whether the current state of <see cref="HealthProcessor"/> or the provided <paramref name="result"/> meets any fail condition.
/// </summary>
/// <param name="result">The judgement result.</param>
private bool meetsAnyFailCondition(JudgementResult result)
{
if (DefaultFailCondition)
return true;
if (FailConditions != null)
{
foreach (var condition in FailConditions.GetInvocationList())
{
bool conditionResult = (bool)condition.Method.Invoke(condition.Target, new object[] { this, result });
if (conditionResult)
return true;
}
}
return false;
}
protected override void Reset(bool storeResults) protected override void Reset(bool storeResults)
{ {
base.Reset(storeResults); base.Reset(storeResults);

View File

@ -99,8 +99,8 @@ namespace osu.Game.Screens.Play.PlayerSettings
{ {
public override LocalisableString TooltipText => public override LocalisableString TooltipText =>
Current.Value == 0 Current.Value == 0
? new TranslatableString("_", @"{0} ms", base.TooltipText) ? LocalisableString.Interpolate($@"{base.TooltipText} ms")
: new TranslatableString("_", @"{0} ms {1}", base.TooltipText, getEarlyLateText(Current.Value)); : LocalisableString.Interpolate($@"{base.TooltipText} ms {getEarlyLateText(Current.Value)}");
private LocalisableString getEarlyLateText(double value) private LocalisableString getEarlyLateText(double value)
{ {

View File

@ -2,27 +2,36 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using osu.Framework.Utils;
namespace osu.Game.Rulesets.Catch.MathUtils namespace osu.Game.Utils
{ {
/// <summary> /// <summary>
/// A PRNG specified in http://heliosphan.org/fastrandom.html. /// A PRNG specified in http://heliosphan.org/fastrandom.html.
/// Should only be used to match legacy behaviour. See <see cref="RNG"/> for a newer alternative.
/// </summary> /// </summary>
public class FastRandom /// <remarks>
/// Known in osu-stable code as `FastRandom`.
/// </remarks>
public class LegacyRandom
{ {
private const double int_to_real = 1.0 / (int.MaxValue + 1.0); private const double int_to_real = 1.0 / (int.MaxValue + 1.0);
private const uint int_mask = 0x7FFFFFFF; private const uint int_mask = 0x7FFFFFFF;
private const uint y_initial = 842502087; private const uint y = 842502087;
private const uint z_initial = 3579807591; private const uint z = 3579807591;
private const uint w_initial = 273326509; private const uint w = 273326509;
private uint x, y = y_initial, z = z_initial, w = w_initial;
public FastRandom(int seed) public uint X { get; private set; }
public uint Y { get; private set; } = y;
public uint Z { get; private set; } = z;
public uint W { get; private set; } = w;
public LegacyRandom(int seed)
{ {
x = (uint)seed; X = (uint)seed;
} }
public FastRandom() public LegacyRandom()
: this(Environment.TickCount) : this(Environment.TickCount)
{ {
} }
@ -33,11 +42,11 @@ namespace osu.Game.Rulesets.Catch.MathUtils
/// <returns>The random value.</returns> /// <returns>The random value.</returns>
public uint NextUInt() public uint NextUInt()
{ {
uint t = x ^ (x << 11); uint t = X ^ (X << 11);
x = y; X = Y;
y = z; Y = Z;
z = w; Z = W;
return w = w ^ (w >> 19) ^ t ^ (t >> 8); return W = W ^ (W >> 19) ^ t ^ (t >> 8);
} }
/// <summary> /// <summary>

View File

@ -35,7 +35,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Realm" Version="10.10.0" /> <PackageReference Include="Realm" Version="10.10.0" />
<PackageReference Include="ppy.osu.Framework" Version="2022.423.0" /> <PackageReference Include="ppy.osu.Framework" Version="2022.428.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" />
<PackageReference Include="Sentry" Version="3.14.1" /> <PackageReference Include="Sentry" Version="3.14.1" />
<PackageReference Include="SharpCompress" Version="0.30.1" /> <PackageReference Include="SharpCompress" Version="0.30.1" />

View File

@ -61,7 +61,7 @@
<Reference Include="System.Net.Http" /> <Reference Include="System.Net.Http" />
</ItemGroup> </ItemGroup>
<ItemGroup Label="Package References"> <ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.423.0" /> <PackageReference Include="ppy.osu.Framework.iOS" Version="2022.428.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" />
</ItemGroup> </ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) --> <!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
@ -84,7 +84,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="ppy.osu.Framework" Version="2022.423.0" /> <PackageReference Include="ppy.osu.Framework" Version="2022.428.0" />
<PackageReference Include="SharpCompress" Version="0.30.1" /> <PackageReference Include="SharpCompress" Version="0.30.1" />
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />