mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:57:36 +08:00
Merge branch 'master' into score-stats-display
This commit is contained in:
commit
cf0b3ec879
@ -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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -35,8 +35,8 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
protected PatternGenerator(LegacyRandom 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));
|
ArgumentNullException.ThrowIfNull(random);
|
||||||
if (originalBeatmap == null) throw new ArgumentNullException(nameof(originalBeatmap));
|
ArgumentNullException.ThrowIfNull(originalBeatmap);
|
||||||
|
|
||||||
Random = random;
|
Random = random;
|
||||||
OriginalBeatmap = originalBeatmap;
|
OriginalBeatmap = originalBeatmap;
|
||||||
|
@ -33,9 +33,9 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns
|
|||||||
|
|
||||||
protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
|
protected PatternGenerator(HitObject hitObject, ManiaBeatmap beatmap, Pattern previousPattern)
|
||||||
{
|
{
|
||||||
if (hitObject == null) throw new ArgumentNullException(nameof(hitObject));
|
ArgumentNullException.ThrowIfNull(hitObject);
|
||||||
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
|
ArgumentNullException.ThrowIfNull(beatmap);
|
||||||
if (previousPattern == null) throw new ArgumentNullException(nameof(previousPattern));
|
ArgumentNullException.ThrowIfNull(previousPattern);
|
||||||
|
|
||||||
HitObject = hitObject;
|
HitObject = hitObject;
|
||||||
Beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
|
@ -22,8 +22,7 @@ namespace osu.Game.Rulesets.Mania.MathUtils
|
|||||||
|
|
||||||
public static void Sort(T[] keys, IComparer<T> comparer)
|
public static void Sort(T[] keys, IComparer<T> comparer)
|
||||||
{
|
{
|
||||||
if (keys == null)
|
ArgumentNullException.ThrowIfNull(keys);
|
||||||
throw new ArgumentNullException(nameof(keys));
|
|
||||||
|
|
||||||
if (keys.Length == 0)
|
if (keys.Length == 0)
|
||||||
return;
|
return;
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
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.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -18,20 +17,18 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
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;
|
private RingExplosion? ringExplosion;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; } = null!;
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
public ArgonJudgementPiece(HitResult result)
|
public ArgonJudgementPiece(HitResult result)
|
||||||
|
: base(result)
|
||||||
{
|
{
|
||||||
Result = result;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
Y = 160;
|
Y = 160;
|
||||||
}
|
}
|
||||||
@ -39,22 +36,6 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
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())
|
if (Result.IsHit())
|
||||||
{
|
{
|
||||||
AddInternal(ringExplosion = new RingExplosion(Result)
|
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>
|
/// <summary>
|
||||||
/// Plays the default animation for this judgement piece.
|
/// Plays the default animation for this judgement piece.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -27,6 +27,10 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
switch (lookup)
|
switch (lookup)
|
||||||
{
|
{
|
||||||
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
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);
|
return new ArgonJudgementPiece(resultComponent.Component);
|
||||||
|
|
||||||
case ManiaSkinComponentLookup maniaComponent:
|
case ManiaSkinComponentLookup maniaComponent:
|
||||||
|
@ -29,8 +29,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
|
|
||||||
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
public ManiaPlayfield(List<StageDefinition> stageDefinitions)
|
||||||
{
|
{
|
||||||
if (stageDefinitions == null)
|
ArgumentNullException.ThrowIfNull(stageDefinitions);
|
||||||
throw new ArgumentNullException(nameof(stageDefinitions));
|
|
||||||
|
|
||||||
if (stageDefinitions.Count <= 0)
|
if (stageDefinitions.Count <= 0)
|
||||||
throw new ArgumentException("Can't have zero or fewer stages.");
|
throw new ArgumentException("Can't have zero or fewer stages.");
|
||||||
|
@ -84,8 +84,8 @@ namespace osu.Game.Rulesets.Osu.Replays
|
|||||||
{
|
{
|
||||||
public int Compare(ReplayFrame? f1, ReplayFrame? f2)
|
public int Compare(ReplayFrame? f1, ReplayFrame? f2)
|
||||||
{
|
{
|
||||||
if (f1 == null) throw new ArgumentNullException(nameof(f1));
|
ArgumentNullException.ThrowIfNull(f1);
|
||||||
if (f2 == null) throw new ArgumentNullException(nameof(f2));
|
ArgumentNullException.ThrowIfNull(f2);
|
||||||
|
|
||||||
return f1.Time.CompareTo(f2.Time);
|
return f1.Time.CompareTo(f2.Time);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
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.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
@ -17,42 +16,24 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
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;
|
private RingExplosion? ringExplosion;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; } = null!;
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
public ArgonJudgementPiece(HitResult result)
|
public ArgonJudgementPiece(HitResult result)
|
||||||
|
: base(result)
|
||||||
{
|
{
|
||||||
Result = result;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
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())
|
if (Result.IsHit())
|
||||||
{
|
{
|
||||||
AddInternal(ringExplosion = new RingExplosion(Result)
|
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>
|
/// <summary>
|
||||||
/// Plays the default animation for this judgement piece.
|
/// Plays the default animation for this judgement piece.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -19,6 +19,10 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
|||||||
switch (lookup)
|
switch (lookup)
|
||||||
{
|
{
|
||||||
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
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);
|
return new ArgonJudgementPiece(resultComponent.Component);
|
||||||
|
|
||||||
case OsuSkinComponentLookup osuComponent:
|
case OsuSkinComponentLookup osuComponent:
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
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.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -18,20 +17,16 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
|
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;
|
private RingExplosion? ringExplosion;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private OsuColour colours { get; set; } = null!;
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
public ArgonJudgementPiece(HitResult result)
|
public ArgonJudgementPiece(HitResult result)
|
||||||
|
: base(result)
|
||||||
{
|
{
|
||||||
Result = result;
|
|
||||||
RelativePositionAxes = Axes.Both;
|
RelativePositionAxes = Axes.Both;
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
@ -39,21 +34,6 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
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())
|
if (Result.IsHit())
|
||||||
{
|
{
|
||||||
AddInternal(ringExplosion = new RingExplosion(Result)
|
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>
|
/// <summary>
|
||||||
/// Plays the default animation for this judgement piece.
|
/// Plays the default animation for this judgement piece.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -19,6 +19,10 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
|
|||||||
switch (component)
|
switch (component)
|
||||||
{
|
{
|
||||||
case GameplaySkinComponentLookup<HitResult> resultComponent:
|
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);
|
return new ArgonJudgementPiece(resultComponent.Component);
|
||||||
|
|
||||||
case TaikoSkinComponentLookup taikoComponent:
|
case TaikoSkinComponentLookup taikoComponent:
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
public partial class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene
|
public partial class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private ZoomableScrollContainer scrollContainer;
|
private TestZoomableScrollContainer scrollContainer;
|
||||||
private Drawable innerBox;
|
private Drawable innerBox;
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -47,7 +47,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = OsuColour.Gray(30)
|
Colour = OsuColour.Gray(30)
|
||||||
},
|
},
|
||||||
scrollContainer = new ZoomableScrollContainer(1, 60, 1)
|
scrollContainer = new TestZoomableScrollContainer(1, 60, 1)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = 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);
|
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]
|
[Test]
|
||||||
public void TestZoom0()
|
public void TestZoom0()
|
||||||
{
|
{
|
||||||
@ -190,5 +198,15 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad;
|
private Quad scrollQuad => scrollContainer.ScreenSpaceDrawQuad;
|
||||||
private Quad boxQuad => innerBox.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,11 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
@ -29,6 +32,15 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("Show main page", () => wiki.Show());
|
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]
|
[Test]
|
||||||
public void TestArticlePage()
|
public void TestArticlePage()
|
||||||
{
|
{
|
||||||
@ -56,7 +68,9 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
public void TestErrorPage()
|
public void TestErrorPage()
|
||||||
{
|
{
|
||||||
setUpWikiResponse(responseArticlePage);
|
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)
|
private void setUpWikiResponse(APIWikiPage r, string redirectionPath = null)
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Tournament.Components
|
|||||||
|
|
||||||
public TournamentBeatmapPanel(TournamentBeatmap beatmap, string mod = null)
|
public TournamentBeatmapPanel(TournamentBeatmap beatmap, string mod = null)
|
||||||
{
|
{
|
||||||
if (beatmap == null) throw new ArgumentNullException(nameof(beatmap));
|
ArgumentNullException.ThrowIfNull(beatmap);
|
||||||
|
|
||||||
Beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
this.mod = mod;
|
this.mod = mod;
|
||||||
|
@ -211,8 +211,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
|||||||
public static T BinarySearch<T>(IReadOnlyList<T> list, double time)
|
public static T BinarySearch<T>(IReadOnlyList<T> list, double time)
|
||||||
where T : class, IControlPoint
|
where T : class, IControlPoint
|
||||||
{
|
{
|
||||||
if (list == null)
|
ArgumentNullException.ThrowIfNull(list);
|
||||||
throw new ArgumentNullException(nameof(list));
|
|
||||||
|
|
||||||
if (list.Count == 0)
|
if (list.Count == 0)
|
||||||
return null;
|
return null;
|
||||||
|
@ -15,8 +15,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
public BeatmapBackgroundSprite(IWorkingBeatmap working)
|
public BeatmapBackgroundSprite(IWorkingBeatmap working)
|
||||||
{
|
{
|
||||||
if (working == null)
|
ArgumentNullException.ThrowIfNull(working);
|
||||||
throw new ArgumentNullException(nameof(working));
|
|
||||||
|
|
||||||
this.working = working;
|
this.working = working;
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,7 @@ namespace osu.Game.Beatmaps.Drawables
|
|||||||
|
|
||||||
public OnlineBeatmapSetCover(IBeatmapSetOnlineInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover)
|
public OnlineBeatmapSetCover(IBeatmapSetOnlineInfo set, BeatmapSetCoverType type = BeatmapSetCoverType.Cover)
|
||||||
{
|
{
|
||||||
if (set == null)
|
ArgumentNullException.ThrowIfNull(set);
|
||||||
throw new ArgumentNullException(nameof(set));
|
|
||||||
|
|
||||||
this.set = set;
|
this.set = set;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
@ -57,8 +57,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
public static Decoder<T> GetDecoder<T>(LineBufferedReader stream)
|
public static Decoder<T> GetDecoder<T>(LineBufferedReader stream)
|
||||||
where T : new()
|
where T : new()
|
||||||
{
|
{
|
||||||
if (stream == null)
|
ArgumentNullException.ThrowIfNull(stream);
|
||||||
throw new ArgumentNullException(nameof(stream));
|
|
||||||
|
|
||||||
if (!decoders.TryGetValue(typeof(T), out var typedDecoders))
|
if (!decoders.TryGetValue(typeof(T), out var typedDecoders))
|
||||||
throw new IOException(@"Unknown decoder type");
|
throw new IOException(@"Unknown decoder type");
|
||||||
|
@ -36,8 +36,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
/// <param name="easing">The easing type of the initial transform.</param>
|
/// <param name="easing">The easing type of the initial transform.</param>
|
||||||
public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None)
|
public void StartTracking(OsuLogo logo, double duration = 0, Easing easing = Easing.None)
|
||||||
{
|
{
|
||||||
if (logo == null)
|
ArgumentNullException.ThrowIfNull(logo);
|
||||||
throw new ArgumentNullException(nameof(logo));
|
|
||||||
|
|
||||||
if (logo.IsTracking && Logo == null)
|
if (logo.IsTracking && Logo == null)
|
||||||
throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s");
|
throw new InvalidOperationException($"Cannot track an instance of {typeof(OsuLogo)} to multiple {typeof(LogoTrackingContainer)}s");
|
||||||
|
@ -52,8 +52,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
|
|
||||||
public readonly SpriteIcon Chevron;
|
public readonly SpriteIcon Chevron;
|
||||||
|
|
||||||
//don't allow clicking between transitions and don't make the chevron clickable
|
//don't allow clicking between transitions
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Alpha == 1f && base.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
public override bool HandleNonPositionalInput => State == Visibility.Visible;
|
public override bool HandleNonPositionalInput => State == Visibility.Visible;
|
||||||
public override bool HandlePositionalInput => 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.Font = Text.Font.With(size: 18);
|
||||||
Text.Margin = new MarginPadding { Vertical = 8 };
|
Text.Margin = new MarginPadding { Vertical = 8 };
|
||||||
Padding = new MarginPadding { Right = padding + ChevronSize };
|
Margin = new MarginPadding { Right = padding + ChevronSize };
|
||||||
Add(Chevron = new SpriteIcon
|
Add(Chevron = new SpriteIcon
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
|
@ -114,8 +114,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
get => current;
|
get => current;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
|
|
||||||
current.UnbindBindings();
|
current.UnbindBindings();
|
||||||
current.BindTo(value);
|
current.BindTo(value);
|
||||||
|
@ -23,8 +23,7 @@ namespace osu.Game.IO.FileAbstraction
|
|||||||
|
|
||||||
public void CloseStream(Stream stream)
|
public void CloseStream(Stream stream)
|
||||||
{
|
{
|
||||||
if (stream == null)
|
ArgumentNullException.ThrowIfNull(stream);
|
||||||
throw new ArgumentNullException(nameof(stream));
|
|
||||||
|
|
||||||
stream.Close();
|
stream.Close();
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,16 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard");
|
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>
|
/// <summary>
|
||||||
/// "You are running the latest release ({0})"
|
/// "You are running the latest release ({0})"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -118,8 +118,7 @@ namespace osu.Game.Online.Chat
|
|||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
public void OpenChannel(string name)
|
public void OpenChannel(string name)
|
||||||
{
|
{
|
||||||
if (name == null)
|
ArgumentNullException.ThrowIfNull(name);
|
||||||
throw new ArgumentNullException(nameof(name));
|
|
||||||
|
|
||||||
CurrentChannel.Value = AvailableChannels.FirstOrDefault(c => c.Name == name) ?? throw new ChannelNotFoundException(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>
|
/// <param name="user">The user the private channel is opened with.</param>
|
||||||
public void OpenPrivateChannel(APIUser user)
|
public void OpenPrivateChannel(APIUser user)
|
||||||
{
|
{
|
||||||
if (user == null)
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
throw new ArgumentNullException(nameof(user));
|
|
||||||
|
|
||||||
if (user.Id == api.LocalUser.Value.Id)
|
if (user.Id == api.LocalUser.Value.Id)
|
||||||
return;
|
return;
|
||||||
|
@ -1040,9 +1040,7 @@ namespace osu.Game
|
|||||||
|
|
||||||
Logger.NewEntry += entry =>
|
Logger.NewEntry += entry =>
|
||||||
{
|
{
|
||||||
if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database) return;
|
if (entry.Level < LogLevel.Important || entry.Target > LoggingTarget.Database || entry.Target == null) return;
|
||||||
|
|
||||||
Debug.Assert(entry.Target != null);
|
|
||||||
|
|
||||||
const int short_term_display_limit = 3;
|
const int short_term_display_limit = 3;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Overlays
|
|||||||
/// <see cref="APIChangelogBuild.DisplayVersion"/> are specified, the header will instantly display them.</param>
|
/// <see cref="APIChangelogBuild.DisplayVersion"/> are specified, the header will instantly display them.</param>
|
||||||
public void ShowBuild([NotNull] APIChangelogBuild build)
|
public void ShowBuild([NotNull] APIChangelogBuild build)
|
||||||
{
|
{
|
||||||
if (build == null) throw new ArgumentNullException(nameof(build));
|
ArgumentNullException.ThrowIfNull(build);
|
||||||
|
|
||||||
Current.Value = build;
|
Current.Value = build;
|
||||||
Show();
|
Show();
|
||||||
@ -78,8 +78,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
public void ShowBuild([NotNull] string updateStream, [NotNull] string version)
|
public void ShowBuild([NotNull] string updateStream, [NotNull] string version)
|
||||||
{
|
{
|
||||||
if (updateStream == null) throw new ArgumentNullException(nameof(updateStream));
|
ArgumentNullException.ThrowIfNull(updateStream);
|
||||||
if (version == null) throw new ArgumentNullException(nameof(version));
|
ArgumentNullException.ThrowIfNull(version);
|
||||||
|
|
||||||
performAfterFetch(() =>
|
performAfterFetch(() =>
|
||||||
{
|
{
|
||||||
|
@ -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>
|
/// <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)
|
public void BeginTracking(object source, ITrackableConfigManager configManager)
|
||||||
{
|
{
|
||||||
if (configManager == null) throw new ArgumentNullException(nameof(configManager));
|
ArgumentNullException.ThrowIfNull(configManager);
|
||||||
|
|
||||||
if (trackedConfigManagers.ContainsKey((source, configManager)))
|
if (trackedConfigManagers.ContainsKey((source, configManager)))
|
||||||
throw new InvalidOperationException($"{nameof(configManager)} is already registered.");
|
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>
|
/// <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)
|
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))
|
if (!trackedConfigManagers.TryGetValue((source, configManager), out var existing))
|
||||||
return;
|
return;
|
||||||
|
@ -7,18 +7,20 @@ using osu.Framework.Allocation;
|
|||||||
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;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
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;
|
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
||||||
|
|
||||||
@ -51,15 +53,32 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private const float size = 4;
|
private const float size = 4;
|
||||||
|
|
||||||
|
private CircularContainer circle = null!;
|
||||||
|
private Box background = null!;
|
||||||
|
|
||||||
|
public RestoreDefaultValueButton()
|
||||||
|
: base(HoverSampleSet.Button)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colour)
|
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);
|
Size = new Vector2(3 * size);
|
||||||
|
|
||||||
Content.RelativeSizeAxes = Axes.None;
|
Add(circle = new CircularContainer
|
||||||
Content.Size = new Vector2(size);
|
{
|
||||||
Content.CornerRadius = size / 2;
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Size = new Vector2(size),
|
||||||
|
Masking = true,
|
||||||
|
Child = background = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = colour.Lime1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Alpha = 0f;
|
Alpha = 0f;
|
||||||
|
|
||||||
@ -77,7 +96,7 @@ namespace osu.Game.Overlays
|
|||||||
FinishTransforms(true);
|
FinishTransforms(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalisableString TooltipText => "revert to default";
|
public override LocalisableString TooltipText => "revert to default";
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
{
|
{
|
||||||
@ -104,8 +123,8 @@ namespace osu.Game.Overlays
|
|||||||
if (!Current.Disabled)
|
if (!Current.Disabled)
|
||||||
{
|
{
|
||||||
this.FadeTo(Current.IsDefault ? 0 : 1, fade_duration, Easing.OutQuint);
|
this.FadeTo(Current.IsDefault ? 0 : 1, fade_duration, Easing.OutQuint);
|
||||||
Background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint);
|
background.FadeColour(IsHovered ? colours.Lime0 : colours.Lime1, fade_duration, Easing.OutQuint);
|
||||||
Content.TweenEdgeEffectTo(new EdgeEffectParameters
|
circle.TweenEdgeEffectTo(new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = (IsHovered ? colours.Lime1 : colours.Lime3).Opacity(0.4f),
|
Colour = (IsHovered ? colours.Lime1 : colours.Lime3).Opacity(0.4f),
|
||||||
Radius = IsHovered ? 8 : 4,
|
Radius = IsHovered ? 8 : 4,
|
||||||
@ -114,8 +133,8 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint);
|
background.FadeColour(colours.Lime3, fade_duration, Easing.OutQuint);
|
||||||
Content.TweenEdgeEffectTo(new EdgeEffectParameters
|
circle.TweenEdgeEffectTo(new EdgeEffectParameters
|
||||||
{
|
{
|
||||||
Colour = colours.Lime3.Opacity(0.1f),
|
Colour = colours.Lime3.Opacity(0.1f),
|
||||||
Radius = 2,
|
Radius = 2,
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Overlays.Settings.Sections.General;
|
using osu.Game.Overlays.Settings.Sections.General;
|
||||||
|
|
||||||
@ -15,7 +14,10 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
public partial class GeneralSection : SettingsSection
|
public partial class GeneralSection : SettingsSection
|
||||||
{
|
{
|
||||||
[Resolved(CanBeNull = true)]
|
[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;
|
public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader;
|
||||||
|
|
||||||
@ -24,15 +26,24 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
Icon = FontAwesome.Solid.Cog
|
Icon = FontAwesome.Solid.Cog
|
||||||
};
|
};
|
||||||
|
|
||||||
public GeneralSection()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
{
|
{
|
||||||
Text = GeneralSettingsStrings.RunSetupWizard,
|
Text = GeneralSettingsStrings.RunSetupWizard,
|
||||||
|
TooltipText = FirstRunSetupOverlayStrings.FirstRunSetupDescription,
|
||||||
Action = () => firstRunSetupOverlay?.Show(),
|
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 LanguageSettings(),
|
||||||
new UpdateSettings(),
|
new UpdateSettings(),
|
||||||
};
|
};
|
||||||
|
@ -28,8 +28,7 @@ namespace osu.Game.Overlays.Volume
|
|||||||
get => current;
|
get => current;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
|
|
||||||
current.UnbindBindings();
|
current.UnbindBindings();
|
||||||
current.BindTo(value);
|
current.BindTo(value);
|
||||||
|
@ -21,6 +21,8 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
private const string index_path = @"main_page";
|
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<string> path = new Bindable<string>(index_path);
|
||||||
|
|
||||||
private readonly Bindable<APIWikiPage> wikiData = new Bindable<APIWikiPage>();
|
private readonly Bindable<APIWikiPage> wikiData = new Bindable<APIWikiPage>();
|
||||||
@ -105,6 +107,9 @@ namespace osu.Game.Overlays
|
|||||||
if (e.NewValue == wikiData.Value?.Path)
|
if (e.NewValue == wikiData.Value?.Path)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (e.NewValue == "error")
|
||||||
|
return;
|
||||||
|
|
||||||
cancellationToken?.Cancel();
|
cancellationToken?.Cancel();
|
||||||
request?.Cancel();
|
request?.Cancel();
|
||||||
|
|
||||||
@ -118,7 +123,11 @@ namespace osu.Game.Overlays
|
|||||||
Loading.Show();
|
Loading.Show();
|
||||||
|
|
||||||
request.Success += response => Schedule(() => onSuccess(response));
|
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);
|
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/",
|
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()
|
private void showParentPage()
|
||||||
|
@ -1,12 +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.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
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.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -15,40 +10,25 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Judgements
|
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)
|
public DefaultJudgementPiece(HitResult result)
|
||||||
{
|
: base(result)
|
||||||
Result = result;
|
|
||||||
Origin = Anchor.Centre;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
Origin = Anchor.Centre;
|
||||||
{
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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>
|
/// <summary>
|
||||||
/// Plays the default animation for this judgement piece.
|
/// Plays the default animation for this judgement piece.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -75,6 +55,6 @@ namespace osu.Game.Rulesets.Judgements
|
|||||||
this.FadeOutFromOne(800);
|
this.FadeOutFromOne(800);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Drawable GetAboveHitObjectsProxiedContent() => null;
|
public Drawable? GetAboveHitObjectsProxiedContent() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
osu.Game/Rulesets/Judgements/JudgementPiece.cs
Normal file
38
osu.Game/Rulesets/Judgements/JudgementPiece.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
@ -126,8 +126,7 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
get => this;
|
get => this;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
|
|
||||||
if (currentBound != null) UnbindFrom(currentBound);
|
if (currentBound != null) UnbindFrom(currentBound);
|
||||||
BindTo(currentBound = value);
|
BindTo(currentBound = value);
|
||||||
|
@ -208,8 +208,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Apply([NotNull] HitObject hitObject)
|
public void Apply([NotNull] HitObject hitObject)
|
||||||
{
|
{
|
||||||
if (hitObject == null)
|
ArgumentNullException.ThrowIfNull(hitObject);
|
||||||
throw new ArgumentNullException($"Cannot apply a null {nameof(HitObject)}.");
|
|
||||||
|
|
||||||
Apply(new SyntheticHitObjectEntry(hitObject));
|
Apply(new SyntheticHitObjectEntry(hitObject));
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
{
|
{
|
||||||
public override void Add(T judgement)
|
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.
|
// remove any existing judgements for the judged object.
|
||||||
// this can be the case when rewinding.
|
// this can be the case when rewinding.
|
||||||
|
@ -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).
|
// 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.
|
// Under no circumstance do we want these to be written to realm as null.
|
||||||
if (model.BeatmapInfo == null) throw new ArgumentNullException(nameof(model.BeatmapInfo));
|
ArgumentNullException.ThrowIfNull(model.BeatmapInfo);
|
||||||
if (model.Ruleset == null) throw new ArgumentNullException(nameof(model.Ruleset));
|
ArgumentNullException.ThrowIfNull(model.Ruleset);
|
||||||
|
|
||||||
PopulateMaximumStatistics(model);
|
PopulateMaximumStatistics(model);
|
||||||
|
|
||||||
|
@ -99,9 +99,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
minZoom = minimum;
|
minZoom = minimum;
|
||||||
maxZoom = maximum;
|
maxZoom = maximum;
|
||||||
CurrentZoom = zoomTarget = initial;
|
|
||||||
isZoomSetUp = true;
|
|
||||||
|
|
||||||
|
CurrentZoom = zoomTarget = initial;
|
||||||
|
zoomedContentWidthCache.Invalidate();
|
||||||
|
|
||||||
|
isZoomSetUp = true;
|
||||||
zoomedContent.Show();
|
zoomedContent.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
|
|
||||||
private void addAmplitudesFromSource(IHasAmplitudes source)
|
private void addAmplitudesFromSource(IHasAmplitudes source)
|
||||||
{
|
{
|
||||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
ArgumentNullException.ThrowIfNull(source);
|
||||||
|
|
||||||
var amplitudes = source.CurrentAmplitudes.FrequencyAmplitudes.Span;
|
var amplitudes = source.CurrentAmplitudes.FrequencyAmplitudes.Span;
|
||||||
|
|
||||||
|
@ -33,8 +33,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
get => current.Current;
|
get => current.Current;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
|
|
||||||
current.Current = value;
|
current.Current = value;
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
get => current.Current;
|
get => current.Current;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == null)
|
ArgumentNullException.ThrowIfNull(value);
|
||||||
throw new ArgumentNullException(nameof(value));
|
|
||||||
|
|
||||||
current.Current = value;
|
current.Current = value;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
public override void Add(KeyCounter key)
|
public override void Add(KeyCounter key)
|
||||||
{
|
{
|
||||||
if (key == null) throw new ArgumentNullException(nameof(key));
|
ArgumentNullException.ThrowIfNull(key);
|
||||||
|
|
||||||
base.Add(key);
|
base.Add(key);
|
||||||
key.IsCounting = IsCounting;
|
key.IsCounting = IsCounting;
|
||||||
|
@ -27,8 +27,7 @@ namespace osu.Game.Users.Drawables
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore ts)
|
private void load(TextureStore ts)
|
||||||
{
|
{
|
||||||
if (ts == null)
|
ArgumentNullException.ThrowIfNull(ts);
|
||||||
throw new ArgumentNullException(nameof(ts));
|
|
||||||
|
|
||||||
string textureName = countryCode == CountryCode.Unknown ? "__" : countryCode.ToString();
|
string textureName = countryCode == CountryCode.Unknown ? "__" : countryCode.ToString();
|
||||||
Texture = ts.Get($@"Flags/{textureName}") ?? ts.Get(@"Flags/__");
|
Texture = ts.Get($@"Flags/{textureName}") ?? ts.Get(@"Flags/__");
|
||||||
|
@ -36,8 +36,7 @@ namespace osu.Game.Users
|
|||||||
protected UserPanel(APIUser user)
|
protected UserPanel(APIUser user)
|
||||||
: base(HoverSampleSet.Button)
|
: base(HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
if (user == null)
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
throw new ArgumentNullException(nameof(user));
|
|
||||||
|
|
||||||
User = user;
|
User = user;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user