1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 22:07:25 +08:00

Merge branch 'master' into score-stats-display

This commit is contained in:
Bartłomiej Dach 2022-12-24 14:32:08 +01:00 committed by GitHub
commit cf0b3ec879
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 251 additions and 377 deletions

View File

@ -1,193 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Catch.Skinning.Argon
{
public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; } = null!;
private RingExplosion? ringExplosion;
[Resolved]
private OsuColour colours { get; set; } = null!;
public ArgonJudgementPiece(HitResult result)
{
Result = result;
Origin = Anchor.Centre;
Y = 160;
}
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
JudgementText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = Result.GetDescription().ToUpperInvariant(),
Colour = colours.ForHitResult(Result),
Blending = BlendingParameters.Additive,
Spacing = new Vector2(10, 0),
Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular),
},
};
if (Result.IsHit())
{
AddInternal(ringExplosion = new RingExplosion(Result)
{
Colour = colours.ForHitResult(Result),
});
}
}
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>
/// <remarks>
/// The base implementation only handles fade (for all result types) and misses.
/// Individual rulesets are recommended to implement their appropriate hit animations.
/// </remarks>
public virtual void PlayAnimation()
{
switch (Result)
{
default:
JudgementText
.ScaleTo(Vector2.One)
.ScaleTo(new Vector2(1.4f), 1800, Easing.OutQuint);
break;
case HitResult.Miss:
this.ScaleTo(1.6f);
this.ScaleTo(1, 100, Easing.In);
this.MoveTo(Vector2.Zero);
this.MoveToOffset(new Vector2(0, 100), 800, Easing.InQuint);
this.RotateTo(0);
this.RotateTo(40, 800, Easing.InQuint);
break;
}
this.FadeOutFromOne(800);
ringExplosion?.PlayAnimation();
}
public Drawable? GetAboveHitObjectsProxiedContent() => null;
private partial class RingExplosion : CompositeDrawable
{
private readonly float travel = 52;
public RingExplosion(HitResult result)
{
const float thickness = 4;
const float small_size = 9;
const float large_size = 14;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Blending = BlendingParameters.Additive;
int countSmall = 0;
int countLarge = 0;
switch (result)
{
case HitResult.Meh:
countSmall = 3;
travel *= 0.3f;
break;
case HitResult.Ok:
case HitResult.Good:
countSmall = 4;
travel *= 0.6f;
break;
case HitResult.Great:
case HitResult.Perfect:
countSmall = 4;
countLarge = 4;
break;
}
for (int i = 0; i < countSmall; i++)
AddInternal(new RingPiece(thickness) { Size = new Vector2(small_size) });
for (int i = 0; i < countLarge; i++)
AddInternal(new RingPiece(thickness) { Size = new Vector2(large_size) });
}
public void PlayAnimation()
{
foreach (var c in InternalChildren)
{
const float start_position_ratio = 0.3f;
float direction = RNG.NextSingle(0, 360);
float distance = RNG.NextSingle(travel / 2, travel);
c.MoveTo(new Vector2(
MathF.Cos(direction) * distance * start_position_ratio,
MathF.Sin(direction) * distance * start_position_ratio
));
c.MoveTo(new Vector2(
MathF.Cos(direction) * distance,
MathF.Sin(direction) * distance
), 600, Easing.OutQuint);
}
this.FadeOutFromOne(1000, Easing.OutQuint);
}
public partial class RingPiece : CircularContainer
{
public RingPiece(float thickness = 9)
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
Masking = true;
BorderThickness = thickness;
BorderColour = Color4.White;
Child = new Box
{
AlwaysPresent = true,
Alpha = 0,
RelativeSizeAxes = Axes.Both
};
}
}
}
}
}

View File

@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
protected PatternGenerator(LegacyRandom random, HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern, IBeatmap originalBeatmap)
: base(hitObject, beatmap, previousPattern)
{
if (random == null) throw new ArgumentNullException(nameof(random));
if (originalBeatmap == null) throw new ArgumentNullException(nameof(originalBeatmap));
ArgumentNullException.ThrowIfNull(random);
ArgumentNullException.ThrowIfNull(originalBeatmap);
Random = random;
OriginalBeatmap = originalBeatmap;

View File

@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
{
if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
ArgumentNullException.ThrowIfNull(hitObject);
ArgumentNullException.ThrowIfNull(beatmap);
ArgumentNullException.ThrowIfNull(previousPattern);
HitObject = hitObject;
Beatmap = beatmap;

View File

@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils
public static void Sort(T[] keys, IComparer<T> comparer)
{
if (keys == null)
throw new ArgumentNullException(nameof(keys));
ArgumentNullException.ThrowIfNull(keys);
if (keys.Length == 0)
return;

View File

@ -3,7 +3,6 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -18,20 +17,18 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Mania.Skinning.Argon
{
public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement
public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; } = null!;
private RingExplosion? ringExplosion;
[Resolved]
private OsuColour colours { get; set; } = null!;
public ArgonJudgementPiece(HitResult result)
: base(result)
{
Result = result;
AutoSizeAxes = Axes.Both;
Origin = Anchor.Centre;
Y = 160;
}
@ -39,22 +36,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
JudgementText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = Result.GetDescription().ToUpperInvariant(),
Colour = colours.ForHitResult(Result),
Blending = BlendingParameters.Additive,
Spacing = new Vector2(10, 0),
Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular),
},
};
if (Result.IsHit())
{
AddInternal(ringExplosion = new RingExplosion(Result)
@ -64,6 +45,16 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
}
}
protected override SpriteText CreateJudgementText() =>
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Blending = BlendingParameters.Additive,
Spacing = new Vector2(10, 0),
Font = OsuFont.Default.With(size: 28, weight: FontWeight.Regular),
};
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>

View File

@ -27,6 +27,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
switch (lookup)
{
case GameplaySkinComponentLookup<HitResult> resultComponent:
// This should eventually be moved to a skin setting, when supported.
if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great)
return Drawable.Empty();
return new ArgonJudgementPiece(resultComponent.Component);
case ManiaSkinComponentLookup maniaComponent:

View File

@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Mania.UI
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
{
if (stageDefinitions == null)
throw new ArgumentNullException(nameof(stageDefinitions));
ArgumentNullException.ThrowIfNull(stageDefinitions);
if (stageDefinitions.Count <= 0)
throw new ArgumentException("Can't have zero or fewer stages.");

View File

@ -84,8 +84,8 @@ namespace osu.Game.Rulesets.Osu.Replays
{
public int Compare(ReplayFrame? f1, ReplayFrame? f2)
{
if (f1 == null) throw new ArgumentNullException(nameof(f1));
if (f2 == null) throw new ArgumentNullException(nameof(f2));
ArgumentNullException.ThrowIfNull(f1);
ArgumentNullException.ThrowIfNull(f2);
return f1.Time.CompareTo(f2.Time);
}

View File

@ -3,7 +3,6 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
@ -17,42 +16,24 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Skinning.Argon
{
public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement
public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; } = null!;
private RingExplosion? ringExplosion;
[Resolved]
private OsuColour colours { get; set; } = null!;
public ArgonJudgementPiece(HitResult result)
: base(result)
{
Result = result;
AutoSizeAxes = Axes.Both;
Origin = Anchor.Centre;
}
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
JudgementText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = Result.GetDescription().ToUpperInvariant(),
Colour = colours.ForHitResult(Result),
Blending = BlendingParameters.Additive,
Spacing = new Vector2(5, 0),
Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold),
},
};
if (Result.IsHit())
{
AddInternal(ringExplosion = new RingExplosion(Result)
@ -62,6 +43,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
}
}
protected override SpriteText CreateJudgementText() =>
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Blending = BlendingParameters.Additive,
Spacing = new Vector2(5, 0),
Font = OsuFont.Default.With(size: 20, weight: FontWeight.Bold),
};
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>

View File

@ -19,6 +19,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
switch (lookup)
{
case GameplaySkinComponentLookup<HitResult> resultComponent:
// This should eventually be moved to a skin setting, when supported.
if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great)
return Drawable.Empty();
return new ArgonJudgementPiece(resultComponent.Component);
case OsuSkinComponentLookup osuComponent:

View File

@ -3,7 +3,6 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@ -18,20 +17,16 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
{
public partial class ArgonJudgementPiece : CompositeDrawable, IAnimatableJudgement
public partial class ArgonJudgementPiece : JudgementPiece, IAnimatableJudgement
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; } = null!;
private RingExplosion? ringExplosion;
[Resolved]
private OsuColour colours { get; set; } = null!;
public ArgonJudgementPiece(HitResult result)
: base(result)
{
Result = result;
RelativePositionAxes = Axes.Both;
RelativeSizeAxes = Axes.Both;
}
@ -39,21 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
[BackgroundDependencyLoader]
private void load()
{
InternalChildren = new Drawable[]
{
JudgementText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = Result.GetDescription().ToUpperInvariant(),
Colour = colours.ForHitResult(Result),
Blending = BlendingParameters.Additive,
Spacing = new Vector2(10, 0),
RelativePositionAxes = Axes.Both,
Font = OsuFont.Default.With(size: 20, weight: FontWeight.Regular),
},
};
if (Result.IsHit())
{
AddInternal(ringExplosion = new RingExplosion(Result)
@ -64,6 +44,17 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
}
}
protected override SpriteText CreateJudgementText() =>
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Blending = BlendingParameters.Additive,
Spacing = new Vector2(10, 0),
RelativePositionAxes = Axes.Both,
Font = OsuFont.Default.With(size: 20, weight: FontWeight.Regular),
};
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>

View File

@ -19,6 +19,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
switch (component)
{
case GameplaySkinComponentLookup<HitResult> resultComponent:
// This should eventually be moved to a skin setting, when supported.
if (Skin is ArgonProSkin && resultComponent.Component >= HitResult.Great)
return Drawable.Empty();
return new ArgonJudgementPiece(resultComponent.Component);
case TaikoSkinComponentLookup taikoComponent:

View File

@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing
{
public partial class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene
{
private ZoomableScrollContainer scrollContainer;
private TestZoomableScrollContainer scrollContainer;
private Drawable innerBox;
[SetUpSteps]
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Editing
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.Gray(30)
},
scrollContainer = new ZoomableScrollContainer(1, 60, 1)
scrollContainer = new TestZoomableScrollContainer(1, 60, 1)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@ -93,6 +93,14 @@ namespace osu.Game.Tests.Visual.Editing
AddAssert("Inner container width matches scroll container", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
}
[Test]
public void TestWidthUpdatesOnSecondZoomSetup()
{
AddAssert("Inner container width = 1x", () => innerBox.DrawWidth == scrollContainer.DrawWidth);
AddStep("reload zoom", () => scrollContainer.SetupZoom(10, 10, 60));
AddAssert("Inner container width = 10x", () => innerBox.DrawWidth == scrollContainer.DrawWidth * 10);
}
[Test]
public void TestZoom0()
{
@ -190,5 +198,15 @@ namespace osu.Game.Tests.Visual.Editing
private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad;
private Quad boxQuad => innerBox.ScreenSpaceDrawQuad;
private partial class TestZoomableScrollContainer : ZoomableScrollContainer
{
public TestZoomableScrollContainer(int minimum, float maximum, float initial)
: base(minimum, maximum, initial)
{
}
public new void SetupZoom(float initial, float minimum, float maximum) => base.SetupZoom(initial, minimum, maximum);
}
}
}

View File

@ -4,8 +4,11 @@
#nullable disable
using System;
using System.Linq;
using System.Net;
using NUnit.Framework;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
@ -29,6 +32,15 @@ namespace osu.Game.Tests.Visual.Online
AddStep("Show main page", () => wiki.Show());
}
[Test]
public void TestCancellationDoesntShowError()
{
AddStep("Show main page", () => wiki.Show());
AddStep("Show another page", () => wiki.ShowPage("Article_styling_criteria/Formatting"));
AddUntilStep("Current path is not error", () => wiki.CurrentPath != "error");
}
[Test]
public void TestArticlePage()
{
@ -56,7 +68,9 @@ namespace osu.Game.Tests.Visual.Online
public void TestErrorPage()
{
setUpWikiResponse(responseArticlePage);
AddStep("Show Error Page", () => wiki.ShowPage("Error"));
AddStep("Show nonexistent page", () => wiki.ShowPage("This_page_will_error_out"));
AddUntilStep("Wait for error page", () => wiki.CurrentPath == "error");
AddUntilStep("Error message correct", () => wiki.ChildrenOfType<SpriteText>().Any(text => text.Text == "\"This_page_will_error_out\"."));
}
private void setUpWikiResponse(APIWikiPage r, string redirectionPath = null)

View File

@ -32,7 +32,7 @@ namespace osu.Game.Tournament.Components
public TournamentBeatmapPanel(TournamentBeatmap beatmap, string mod = null)
{
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
ArgumentNullException.ThrowIfNull(beatmap);
Beatmap = beatmap;
this.mod = mod;

View File

@ -211,8 +211,7 @@ namespace osu.Game.Beatmaps.ControlPoints
public static T BinarySearch<T>(IReadOnlyList<T> list, double time)
where T : class, IControlPoint
{
if (list == null)
throw new ArgumentNullException(nameof(list));
ArgumentNullException.ThrowIfNull(list);
if (list.Count == 0)
return null;

View File

@ -15,8 +15,7 @@ namespace osu.Game.Beatmaps.Drawables
public BeatmapBackgroundSprite(IWorkingBeatmap working)
{
if (working == null)
throw new ArgumentNullException(nameof(working));
ArgumentNullException.ThrowIfNull(working);
this.working = working;
}

View File

@ -18,8 +18,7 @@ namespace osu.Game.Beatmaps.Drawables
public OnlineBeatmapSetCover(IBeatmapSetOnlineInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover)
{
if (set == null)
throw new ArgumentNullException(nameof(set));
ArgumentNullException.ThrowIfNull(set);
this.set = set;
this.type = type;

View File

@ -57,8 +57,7 @@ namespace osu.Game.Beatmaps.Formats
public static Decoder<T> GetDecoder<T>(LineBufferedReader stream)
where T : new()
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
ArgumentNullException.ThrowIfNull(stream);
if (!decoders.TryGetValue(typeof(T), out var typedDecoders))
throw new IOException(@"Unknown decoder type");

View File

@ -36,8 +36,7 @@ namespace osu.Game.Graphics.Containers
/// <param name="easing">The easing type of the initial transform.</param>
public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None)
{
if (logo == null)
throw new ArgumentNullException(nameof(logo));
ArgumentNullException.ThrowIfNull(logo);
if (logo.IsTracking && Logo == null)
throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s");

View File

@ -52,8 +52,8 @@ namespace osu.Game.Graphics.UserInterface
public readonly SpriteIcon Chevron;
//don't allow clicking between transitions and don't make the chevron clickable
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceivePositionalInputAt(screenSpacePos);
//don't allow clicking between transitions
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Alpha == 1f && base.ReceivePositionalInputAt(screenSpacePos);
public override bool HandleNonPositionalInput => State == Visibility.Visible;
public override bool HandlePositionalInput => State == Visibility.Visible;
@ -95,7 +95,7 @@ namespace osu.Game.Graphics.UserInterface
{
Text.Font = Text.Font.With(size: 18);
Text.Margin = new MarginPadding { Vertical = 8 };
Padding = new MarginPadding { Right = padding + ChevronSize };
Margin = new MarginPadding { Right = padding + ChevronSize };
Add(Chevron = new SpriteIcon
{
Anchor = Anchor.CentreRight,

View File

@ -114,8 +114,7 @@ namespace osu.Game.Graphics.UserInterface
get => current;
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
ArgumentNullException.ThrowIfNull(value);
current.UnbindBindings();
current.BindTo(value);

View File

@ -23,8 +23,7 @@ namespace osu.Game.IO.FileAbstraction
public void CloseStream(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));
ArgumentNullException.ThrowIfNull(stream);
stream.Close();
}

View File

@ -64,6 +64,16 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard");
/// <summary>
/// "Learn more about lazer"
/// </summary>
public static LocalisableString LearnMoreAboutLazer => new TranslatableString(getKey(@"learn_more_about_lazer"), @"Learn more about lazer");
/// <summary>
/// "Check out the feature comparison and FAQ"
/// </summary>
public static LocalisableString LearnMoreAboutLazerTooltip => new TranslatableString(getKey(@"check_out_the_feature_comparison"), @"Check out the feature comparison and FAQ");
/// <summary>
/// "You are running the latest release ({0})"
/// </summary>

View File

@ -118,8 +118,7 @@ namespace osu.Game.Online.Chat
/// <param name="name"></param>
public void OpenChannel(string name)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
ArgumentNullException.ThrowIfNull(name);
CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) ?? throw new ChannelNotFoundException(name);
}
@ -130,8 +129,7 @@ namespace osu.Game.Online.Chat
/// <param name="user">The user the private channel is opened with.</param>
public void OpenPrivateChannel(APIUser user)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
ArgumentNullException.ThrowIfNull(user);
if (user.Id == api.LocalUser.Value.Id)
return;

View File

@ -1040,9 +1040,7 @@ namespace osu.Game
Logger.NewEntry += entry =>
{
if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database) return;
Debug.Assert(entry.Target != null);
if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database || entry.Target == null) return;
const int short_term_display_limit = 3;

View File

@ -70,7 +70,7 @@ namespace osu.Game.Overlays
/// <see cref="APIChangelogBuild.DisplayVersion"/> are specified, the header will instantly display them.</param>
public void ShowBuild([NotNull] APIChangelogBuild build)
{
if (build == null) throw new ArgumentNullException(nameof(build));
ArgumentNullException.ThrowIfNull(build);
Current.Value = build;
Show();
@ -78,8 +78,8 @@ namespace osu.Game.Overlays
public void ShowBuild([NotNull] string updateStream, [NotNull] string version)
{
if (updateStream == null) throw new ArgumentNullException(nameof(updateStream));
if (version == null) throw new ArgumentNullException(nameof(version));
ArgumentNullException.ThrowIfNull(updateStream);
ArgumentNullException.ThrowIfNull(version);
performAfterFetch(() =>
{

View File

@ -58,7 +58,7 @@ namespace osu.Game.Overlays
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is already being tracked from the same <paramref name="source"/>.</exception>
public void BeginTracking(object source, ITrackableConfigManager configManager)
{
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
ArgumentNullException.ThrowIfNull(configManager);
if (trackedConfigManagers.ContainsKey((source, configManager)))
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
@ -82,7 +82,7 @@ namespace osu.Game.Overlays
/// <exception cref="InvalidOperationException">If <paramref name="configManager"/> is not being tracked from the same <paramref name="source"/>.</exception>
public void StopTracking(object source, ITrackableConfigManager configManager)
{
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
ArgumentNullException.ThrowIfNull(configManager);
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
return;

View File

@ -7,18 +7,20 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osuTK;
namespace osu.Game.Overlays
{
public partial class RestoreDefaultValueButton<T> : OsuButton, IHasTooltip, IHasCurrentValue<T>
public partial class RestoreDefaultValueButton<T> : OsuClickableContainer, IHasCurrentValue<T>
{
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
@ -51,15 +53,32 @@ namespace osu.Game.Overlays
private const float size = 4;
private CircularContainer circle = null!;
private Box background = null!;
public RestoreDefaultValueButton()
: base(HoverSampleSet.Button)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colour)
{
BackgroundColour = colour.Lime1;
// size intentionally much larger than actual drawn content, so that the button is easier to click.
Size = new Vector2(3 * size);
Content.RelativeSizeAxes = Axes.None;
Content.Size = new Vector2(size);
Content.CornerRadius = size / 2;
Add(circle = new CircularContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(size),
Masking = true,
Child = background = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colour.Lime1
}
});
Alpha = 0f;
@ -77,7 +96,7 @@ namespace osu.Game.Overlays
FinishTransforms(true);
}
public LocalisableString TooltipText => "revert to default";
public override LocalisableString TooltipText => "revert to default";
protected override bool OnHover(HoverEvent e)
{
@ -104,8 +123,8 @@ namespace osu.Game.Overlays
if (!Current.Disabled)
{
this.FadeTo(Current.IsDefault ? 0 : 1, fade_duration, Easing.OutQuint);
Background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint);
Content.TweenEdgeEffectTo(new EdgeEffectParameters
background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint);
circle.TweenEdgeEffectTo(new EdgeEffectParameters
{
Colour = (IsHovered ? colours.Lime1 : colours.Lime3).Opacity(0.4f),
Radius = IsHovered ? 8 : 4,
@ -114,8 +133,8 @@ namespace osu.Game.Overlays
}
else
{
Background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint);
Content.TweenEdgeEffectTo(new EdgeEffectParameters
background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint);
circle.TweenEdgeEffectTo(new EdgeEffectParameters
{
Colour = colours.Lime3.Opacity(0.1f),
Radius = 2,

View File

@ -1,12 +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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Localisation;
using osu.Game.Overlays.Settings.Sections.General;
@ -15,7 +14,10 @@ namespace osu.Game.Overlays.Settings.Sections
public partial class GeneralSection : SettingsSection
{
[Resolved(CanBeNull = true)]
private FirstRunSetupOverlay firstRunSetupOverlay { get; set; }
private FirstRunSetupOverlay? firstRunSetupOverlay { get; set; }
[Resolved(CanBeNull = true)]
private OsuGame? game { get; set; }
public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader;
@ -24,15 +26,24 @@ namespace osu.Game.Overlays.Settings.Sections
Icon = FontAwesome.Solid.Cog
};
public GeneralSection()
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Children = new Drawable[]
{
new SettingsButton
{
Text = GeneralSettingsStrings.RunSetupWizard,
TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription,
Action = () => firstRunSetupOverlay?.Show(),
},
new SettingsButton
{
Text = GeneralSettingsStrings.LearnMoreAboutLazer,
TooltipText = GeneralSettingsStrings.LearnMoreAboutLazerTooltip,
BackgroundColour = colours.YellowDark,
Action = () => game?.ShowWiki(@"Help_centre/Upgrading_to_lazer")
},
new LanguageSettings(),
new UpdateSettings(),
};

View File

@ -28,8 +28,7 @@ namespace osu.Game.Overlays.Volume
get => current;
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
ArgumentNullException.ThrowIfNull(value);
current.UnbindBindings();
current.BindTo(value);

View File

@ -21,6 +21,8 @@ namespace osu.Game.Overlays
{
private const string index_path = @"main_page";
public string CurrentPath => path.Value;
private readonly Bindable<string> path = new Bindable<string>(index_path);
private readonly Bindable<APIWikiPage> wikiData = new Bindable<APIWikiPage>();
@ -105,6 +107,9 @@ namespace osu.Game.Overlays
if (e.NewValue == wikiData.Value?.Path)
return;
if (e.NewValue == "error")
return;
cancellationToken?.Cancel();
request?.Cancel();
@ -118,7 +123,11 @@ namespace osu.Game.Overlays
Loading.Show();
request.Success += response => Schedule(() => onSuccess(response));
request.Failure += _ => Schedule(onFail);
request.Failure += ex =>
{
if (ex is not OperationCanceledException)
Schedule(onFail, request.Path);
};
api.PerformAsync(request);
}
@ -146,10 +155,11 @@ namespace osu.Game.Overlays
}
}
private void onFail()
private void onFail(string originalPath)
{
path.Value = "error";
LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/",
$"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page)."));
$"Something went wrong when trying to fetch page \"{originalPath}\".\n\n[Return to the main page](Main_Page)."));
}
private void showParentPage()

View File

@ -1,12 +1,7 @@
// 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.
#nullable disable
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@ -15,40 +10,25 @@ using osuTK;
namespace osu.Game.Rulesets.Judgements
{
public partial class DefaultJudgementPiece : CompositeDrawable, IAnimatableJudgement
public partial class DefaultJudgementPiece : JudgementPiece, IAnimatableJudgement
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; }
[Resolved]
private OsuColour colours { get; set; }
public DefaultJudgementPiece(HitResult result)
{
Result = result;
Origin = Anchor.Centre;
}
[BackgroundDependencyLoader]
private void load()
: base(result)
{
AutoSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
JudgementText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = Result.GetDescription().ToUpperInvariant(),
Colour = colours.ForHitResult(Result),
Font = OsuFont.Numeric.With(size: 20),
Scale = new Vector2(0.85f, 1),
}
};
Origin = Anchor.Centre;
}
protected override SpriteText CreateJudgementText() =>
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Numeric.With(size: 20),
Scale = new Vector2(0.85f, 1),
};
/// <summary>
/// Plays the default animation for this judgement piece.
/// </summary>
@ -75,6 +55,6 @@ namespace osu.Game.Rulesets.Judgements
this.FadeOutFromOne(800);
}
public Drawable GetAboveHitObjectsProxiedContent() => null;
public Drawable? GetAboveHitObjectsProxiedContent() => null;
}
}

View File

@ -0,0 +1,38 @@
// 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.Extensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Judgements
{
public abstract partial class JudgementPiece : CompositeDrawable
{
protected readonly HitResult Result;
protected SpriteText JudgementText { get; private set; } = null!;
[Resolved]
private OsuColour colours { get; set; } = null!;
protected JudgementPiece(HitResult result)
{
Result = result;
}
[BackgroundDependencyLoader]
private void load()
{
AddInternal(JudgementText = CreateJudgementText());
JudgementText.Colour = colours.ForHitResult(Result);
JudgementText.Text = Result.GetDescription().ToUpperInvariant();
}
protected abstract SpriteText CreateJudgementText();
}
}

View File

@ -126,8 +126,7 @@ namespace osu.Game.Rulesets.Mods
get => this;
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
ArgumentNullException.ThrowIfNull(value);
if (currentBound != null) UnbindFrom(currentBound);
BindTo(currentBound = value);

View File

@ -208,8 +208,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// </summary>
public void Apply([NotNull] HitObject hitObject)
{
if (hitObject == null)
throw new ArgumentNullException($"Cannot apply a null {nameof(HitObject)}.");
ArgumentNullException.ThrowIfNull(hitObject);
Apply(new SyntheticHitObjectEntry(hitObject));
}

View File

@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.UI
{
public override void Add(T judgement)
{
if (judgement == null) throw new ArgumentNullException(nameof(judgement));
ArgumentNullException.ThrowIfNull(judgement);
// remove any existing judgements for the judged object.
// this can be the case when rewinding.

View File

@ -71,8 +71,8 @@ namespace osu.Game.Scoring
// These properties are known to be non-null, but these final checks ensure a null hasn't come from somewhere (or the refetch has failed).
// Under no circumstance do we want these to be written to realm as null.
if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo));
if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset));
ArgumentNullException.ThrowIfNull(model.BeatmapInfo);
ArgumentNullException.ThrowIfNull(model.Ruleset);
PopulateMaximumStatistics(model);

View File

@ -99,9 +99,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
minZoom = minimum;
maxZoom = maximum;
CurrentZoom = zoomTarget = initial;
isZoomSetUp = true;
CurrentZoom = zoomTarget = initial;
zoomedContentWidthCache.Invalidate();
isZoomSetUp = true;
zoomedContent.Show();
}

View File

@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu
private void addAmplitudesFromSource(IHasAmplitudes source)
{
if (source == null) throw new ArgumentNullException(nameof(source));
ArgumentNullException.ThrowIfNull(source);
var amplitudes = source.CurrentAmplitudes.FrequencyAmplitudes.Span;

View File

@ -33,8 +33,7 @@ namespace osu.Game.Screens.Play.HUD
get => current.Current;
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
ArgumentNullException.ThrowIfNull(value);
current.Current = value;
}

View File

@ -30,8 +30,7 @@ namespace osu.Game.Screens.Play.HUD
get => current.Current;
set
{
if (value == null)
throw new ArgumentNullException(nameof(value));
ArgumentNullException.ThrowIfNull(value);
current.Current = value;
}

View File

@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
if (key == null) throw new ArgumentNullException(nameof(key));
ArgumentNullException.ThrowIfNull(key);
base.Add(key);
key.IsCounting = IsCounting;

View File

@ -27,8 +27,7 @@ namespace osu.Game.Users.Drawables
[BackgroundDependencyLoader]
private void load(TextureStore ts)
{
if (ts == null)
throw new ArgumentNullException(nameof(ts));
ArgumentNullException.ThrowIfNull(ts);
string textureName = countryCode == CountryCode.Unknown ? "__" : countryCode.ToString();
Texture = ts.Get($@"Flags/{textureName}") ?? ts.Get(@"Flags/__");

View File

@ -36,8 +36,7 @@ namespace osu.Game.Users
protected UserPanel(APIUser user)
: base(HoverSampleSet.Button)
{
if (user == null)
throw new ArgumentNullException(nameof(user));
ArgumentNullException.ThrowIfNull(user);
User = user;
}