From dc75d55f72af11bdf81b081dad8f5e84be3ed2e2 Mon Sep 17 00:00:00 2001
From: Gabe Livengood <47010459+ggliv@users.noreply.github.com>
Date: Wed, 8 Jun 2022 14:02:15 -0400
Subject: [PATCH 001/476] allow modfailcondition to arbitrarily trigger fail
---
osu.Game/Rulesets/Mods/ModFailCondition.cs | 19 +++++++++++++++++++
osu.Game/Rulesets/Scoring/HealthProcessor.cs | 14 ++++++++++----
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs
index 4425ece513..1aab0ab880 100644
--- a/osu.Game/Rulesets/Mods/ModFailCondition.cs
+++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs
@@ -19,12 +19,31 @@ namespace osu.Game.Rulesets.Mods
public virtual bool PerformFail() => true;
public virtual bool RestartOnFail => Restart.Value;
+ private HealthProcessor healthProcessorInternal;
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
{
+ healthProcessorInternal = healthProcessor;
healthProcessor.FailConditions += FailCondition;
}
+ ///
+ /// Immediately triggers a failure on the loaded .
+ ///
+ protected void TriggerArbitraryFailure() => healthProcessorInternal.TriggerFailure();
+
+ ///
+ /// Determines whether should trigger a failure. Called every time a
+ /// judgement is applied to .
+ ///
+ /// The loaded .
+ /// The latest .
+ /// Whether the fail condition has been met.
+ ///
+ /// This method should only be used to trigger failures based on .
+ /// Using outside values to evaluate failure may introduce event ordering discrepancies, use
+ /// an with instead.
+ ///
protected abstract bool FailCondition(HealthProcessor healthProcessor, JudgementResult result);
}
}
diff --git a/osu.Game/Rulesets/Scoring/HealthProcessor.cs b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
index 0f51560476..4f5ff95477 100644
--- a/osu.Game/Rulesets/Scoring/HealthProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/HealthProcessor.cs
@@ -33,6 +33,15 @@ namespace osu.Game.Rulesets.Scoring
///
public bool HasFailed { get; private set; }
+ ///
+ /// Immediately triggers a failure for this HealthProcessor.
+ ///
+ public void TriggerFailure()
+ {
+ if (Failed?.Invoke() != false)
+ HasFailed = true;
+ }
+
protected override void ApplyResultInternal(JudgementResult result)
{
result.HealthAtJudgement = Health.Value;
@@ -44,10 +53,7 @@ namespace osu.Game.Rulesets.Scoring
Health.Value += GetHealthIncreaseFor(result);
if (meetsAnyFailCondition(result))
- {
- if (Failed?.Invoke() != false)
- HasFailed = true;
- }
+ TriggerFailure();
}
protected override void RevertResultInternal(JudgementResult result)
From 21c5499da16eb88f12d6f5bee8d28b1557559b2f Mon Sep 17 00:00:00 2001
From: Gabe Livengood <47010459+ggliv@users.noreply.github.com>
Date: Fri, 10 Jun 2022 13:11:17 -0400
Subject: [PATCH 002/476] remove arbitrary from method name
---
osu.Game/Rulesets/Mods/ModFailCondition.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs
index 1aab0ab880..9500734408 100644
--- a/osu.Game/Rulesets/Mods/ModFailCondition.cs
+++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Rulesets.Mods
///
/// Immediately triggers a failure on the loaded .
///
- protected void TriggerArbitraryFailure() => healthProcessorInternal.TriggerFailure();
+ protected void TriggerFailure() => healthProcessorInternal.TriggerFailure();
///
/// Determines whether should trigger a failure. Called every time a
@@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.Mods
///
/// This method should only be used to trigger failures based on .
/// Using outside values to evaluate failure may introduce event ordering discrepancies, use
- /// an with instead.
+ /// an with instead.
///
protected abstract bool FailCondition(HealthProcessor healthProcessor, JudgementResult result);
}
From 6e64a8f55ef5838a5d58625668138fb3c85e34db Mon Sep 17 00:00:00 2001
From: Gabe Livengood <47010459+ggliv@users.noreply.github.com>
Date: Fri, 10 Jun 2022 13:13:35 -0400
Subject: [PATCH 003/476] use event to trigger failure
---
osu.Game/Rulesets/Mods/ModFailCondition.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs
index 9500734408..63cebc9747 100644
--- a/osu.Game/Rulesets/Mods/ModFailCondition.cs
+++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs
@@ -19,18 +19,18 @@ namespace osu.Game.Rulesets.Mods
public virtual bool PerformFail() => true;
public virtual bool RestartOnFail => Restart.Value;
- private HealthProcessor healthProcessorInternal;
+ private event Action failureTriggered;
public void ApplyToHealthProcessor(HealthProcessor healthProcessor)
{
- healthProcessorInternal = healthProcessor;
+ failureTriggered = healthProcessor.TriggerFailure;
healthProcessor.FailConditions += FailCondition;
}
///
/// Immediately triggers a failure on the loaded .
///
- protected void TriggerFailure() => healthProcessorInternal.TriggerFailure();
+ protected void TriggerFailure() => failureTriggered?.Invoke();
///
/// Determines whether should trigger a failure. Called every time a
From c1077d909ca5e41270522714e8457733a36043f2 Mon Sep 17 00:00:00 2001
From: Ryuki
Date: Sat, 17 Sep 2022 21:09:34 +0200
Subject: [PATCH 004/476] Basic avatar HUD implementation
---
osu.Game/Screens/Play/HUD/SkinnableAvatar.cs | 50 ++++++++++++++++++++
1 file changed, 50 insertions(+)
create mode 100644 osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
new file mode 100644
index 0000000000..abec4402a7
--- /dev/null
+++ b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
@@ -0,0 +1,50 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Configuration;
+using osu.Game.Skinning;
+using osu.Game.Users.Drawables;
+using osuTK;
+
+namespace osu.Game.Screens.Play.HUD
+{
+ public class SkinnableAvatar : CompositeDrawable, ISkinnableDrawable
+ {
+ [SettingSource("Corner radius", "How much the edges should be rounded.")]
+ public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0)
+ {
+ MinValue = 0,
+ MaxValue = 100,
+ Precision = 0.01f
+ };
+
+ [Resolved]
+ private GameplayState gameplayState { get; set; } = null!;
+
+ private readonly UpdateableAvatar avatar;
+
+ public SkinnableAvatar()
+ {
+ Size = new Vector2(128f);
+ InternalChild = avatar = new UpdateableAvatar(isInteractive: false)
+ {
+ RelativeSizeAxes = Axes.Both,
+ Masking = true
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ avatar.User = gameplayState.Score.ScoreInfo.User;
+ CornerRadius.BindValueChanged(e => avatar.CornerRadius = e.NewValue);
+ }
+
+ public bool UsesFixedAnchor { get; set; }
+ }
+}
From ecf71df8a23bfca5cbe5a78daef23908135d92c2 Mon Sep 17 00:00:00 2001
From: Ryuki
Date: Sun, 18 Sep 2022 00:04:56 +0200
Subject: [PATCH 005/476] Change CornerRadius Max Value
---
osu.Game/Screens/Play/HUD/SkinnableAvatar.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
index abec4402a7..d675176a0a 100644
--- a/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
+++ b/osu.Game/Screens/Play/HUD/SkinnableAvatar.cs
@@ -15,10 +15,10 @@ namespace osu.Game.Screens.Play.HUD
public class SkinnableAvatar : CompositeDrawable, ISkinnableDrawable
{
[SettingSource("Corner radius", "How much the edges should be rounded.")]
- public new BindableFloat CornerRadius { get; set; } = new BindableFloat(0)
+ public new BindableFloat CornerRadius { get; set; } = new BindableFloat
{
MinValue = 0,
- MaxValue = 100,
+ MaxValue = 63,
Precision = 0.01f
};
From bbb22479a8aefd1b040d236dde395c0220ed4bc4 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sun, 25 Dec 2022 21:32:47 +0100
Subject: [PATCH 006/476] Add "ModBubbles" for the osu ruleset.
---
.../Mods/TestSceneOsuModBubbles.cs | 19 ++
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 228 ++++++++++++++++++
osu.Game.Rulesets.Osu/OsuRuleset.cs | 3 +-
osu.Game/Rulesets/Mods/ModFlashlight.cs | 3 +
4 files changed, 252 insertions(+), 1 deletion(-)
create mode 100644 osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs
create mode 100644 osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs
new file mode 100644
index 0000000000..e72a1f79f5
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModBubbles.cs
@@ -0,0 +1,19 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Osu.Mods;
+
+namespace osu.Game.Rulesets.Osu.Tests.Mods
+{
+ public partial class TestSceneOsuModBubbles : OsuModTestScene
+ {
+ [Test]
+ public void TestOsuModBubbles() => CreateModTest(new ModTestData
+ {
+ Mod = new OsuModBubbles(),
+ Autoplay = true,
+ PassCondition = () => true
+ });
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
new file mode 100644
index 0000000000..c51ebde383
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -0,0 +1,228 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Effects;
+using osu.Framework.Graphics.Performance;
+using osu.Framework.Graphics.Pooling;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Localisation;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Objects.Pooling;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.UI;
+using osu.Game.Scoring;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ public partial class OsuModBubbles : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset, IApplicableToScoreProcessor
+ {
+ public override string Name => "Bubbles";
+
+ public override string Acronym => "BB";
+
+ public override LocalisableString Description => "Dont let their popping distract you!";
+
+ public override double ScoreMultiplier => 1;
+
+ public override ModType Type => ModType.Fun;
+
+ // Compatibility with these seems potentially feasible in the future, blocked for now because they dont work as one would expect
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
+
+ private PlayfieldAdjustmentContainer adjustmentContainer = null!;
+ private BubbleContainer bubbleContainer = null!;
+
+ private readonly Bindable currentCombo = new BindableInt();
+
+ private float maxSize;
+ private float bubbleRadius;
+ private double bubbleFade;
+
+ public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
+
+ public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
+ {
+ currentCombo.BindTo(scoreProcessor.Combo);
+ currentCombo.BindValueChanged(combo =>
+ maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
+ }
+
+ public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
+ {
+ // Multiplying by 2 results in an initial size that is too large, hence 1.85 has been chosen
+ bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.85f);
+ bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimeFadeIn * 2;
+
+ // We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
+ drawableRuleset.Playfield.DisplayJudgements.Value = false;
+
+ adjustmentContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
+
+ adjustmentContainer.Add(bubbleContainer = new BubbleContainer());
+ drawableRuleset.KeyBindingInputManager.Add(adjustmentContainer);
+ }
+
+ protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
+
+ protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
+
+ private void applyBubbleState(DrawableHitObject drawableObject)
+ {
+ if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
+
+ OsuHitObject hitObject = drawableOsuObject.HitObject;
+
+ switch (drawableOsuObject)
+ {
+ //Needs to be done explicitly to avoid being handled by DrawableHitCircle below
+ case DrawableSliderHead:
+ addBubbleContainer(hitObject.Position);
+ break;
+
+ //Stack leniency causes placement issues if this isn't handled as such.
+ case DrawableHitCircle hitCircle:
+ addBubbleContainer(hitCircle.Position);
+ break;
+
+ case DrawableSpinnerTick:
+ case DrawableSlider:
+ return;
+
+ default:
+ addBubbleContainer(hitObject.Position);
+ break;
+ }
+
+ void addBubbleContainer(Vector2 position) => bubbleContainer.Add(new BubbleLifeTimeEntry
+ {
+ LifetimeStart = bubbleContainer.Time.Current,
+ Colour = drawableOsuObject.AccentColour.Value,
+ Position = position,
+ InitialSize = new Vector2(bubbleRadius),
+ MaxSize = maxSize,
+ FadeTime = bubbleFade,
+ IsHit = drawableOsuObject.IsHit
+ }
+ );
+ }
+
+ #region Pooled Bubble drawable
+
+ //LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
+ //Todo: find solution to bubbles rewinding in "groups"
+ private sealed partial class BubbleContainer : PooledDrawableWithLifetimeContainer
+ {
+ protected override bool RemoveRewoundEntry => true;
+
+ private readonly DrawablePool pool;
+
+ public BubbleContainer()
+ {
+ RelativeSizeAxes = Axes.Both;
+ AddInternal(pool = new DrawablePool(10, 1000));
+ }
+
+ protected override BubbleObject GetDrawable(BubbleLifeTimeEntry entry) => pool.Get(d => d.Apply(entry));
+ }
+
+ private sealed partial class BubbleObject : PoolableDrawableWithLifetime
+ {
+ private readonly BubbleDrawable bubbleDrawable;
+
+ public BubbleObject()
+ {
+ InternalChild = bubbleDrawable = new BubbleDrawable();
+ }
+
+ protected override void OnApply(BubbleLifeTimeEntry entry)
+ {
+ base.OnApply(entry);
+ if (IsLoaded)
+ apply(entry);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ apply(Entry);
+ }
+
+ private void apply(BubbleLifeTimeEntry? entry)
+ {
+ if (entry == null)
+ return;
+
+ ApplyTransformsAt(float.MinValue, true);
+ ClearTransforms(true);
+
+ Position = entry.Position;
+
+ bubbleDrawable.Animate(entry);
+
+ LifetimeEnd = bubbleDrawable.LatestTransformEndTime;
+ }
+ }
+
+ private partial class BubbleDrawable : CompositeDrawable
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChild = new Circle
+ {
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Colour = Colour4.Black.Opacity(0.05f),
+ Type = EdgeEffectType.Shadow,
+ Radius = 5
+ }
+ };
+ }
+
+ public void Animate(BubbleLifeTimeEntry entry)
+ {
+ Size = entry.InitialSize;
+ this
+ .ScaleTo(entry.MaxSize, entry.FadeTime * 6, Easing.OutSine)
+ .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
+ .Delay(entry.FadeTime)
+ .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine)
+ .Then()
+ .ScaleTo(entry.MaxSize * 1.5f, entry.FadeTime, Easing.OutSine)
+ .FadeTo(0, entry.FadeTime, Easing.OutQuint);
+ }
+ }
+
+ private class BubbleLifeTimeEntry : LifetimeEntry
+ {
+ public Vector2 InitialSize { get; set; }
+
+ public float MaxSize { get; set; }
+
+ public Vector2 Position { get; set; }
+
+ public Colour4 Colour { get; set; }
+
+ // FadeTime is based on the approach rate of the beatmap.
+ public double FadeTime { get; set; }
+
+ // Whether the corresponding HitObject was hit
+ public bool IsHit { get; set; }
+ }
+
+ #endregion
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 79a566e33c..0df1e4dfca 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -202,7 +202,8 @@ namespace osu.Game.Rulesets.Osu
new OsuModNoScope(),
new MultiMod(new OsuModMagnetised(), new OsuModRepel()),
new ModAdaptiveSpeed(),
- new OsuModFreezeFrame()
+ new OsuModFreezeFrame(),
+ new OsuModBubbles()
};
case ModType.System:
diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs
index 45fa55c7f2..2c9ef357b5 100644
--- a/osu.Game/Rulesets/Mods/ModFlashlight.cs
+++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs
@@ -83,6 +83,9 @@ namespace osu.Game.Rulesets.Mods
flashlight.Combo.BindTo(Combo);
drawableRuleset.KeyBindingInputManager.Add(flashlight);
+
+ // Stop flashlight from being drawn underneath other mods that generate HitObjects.
+ drawableRuleset.KeyBindingInputManager.ChangeChildDepth(flashlight, -1);
}
protected abstract Flashlight CreateFlashlight();
From 8a108b143e10bf80162eb0109aad7a68ae9692fc Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sun, 25 Dec 2022 21:33:10 +0100
Subject: [PATCH 007/476] Address mod incompatibilities
---
osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs | 3 +++
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 17 +++++++++++------
osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs | 2 +-
osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs | 2 +-
4 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
index 9e71f657ce..2394cf92fc 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBarrelRoll.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
@@ -10,6 +11,8 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public class OsuModBarrelRoll : ModBarrelRoll, IApplicableToDrawableHitObject
{
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModBubbles) };
+
public void ApplyToDrawableHitObject(DrawableHitObject d)
{
d.OnUpdate += _ =>
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index c51ebde383..2e4d574148 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -86,12 +86,12 @@ namespace osu.Game.Rulesets.Osu.Mods
{
//Needs to be done explicitly to avoid being handled by DrawableHitCircle below
case DrawableSliderHead:
- addBubbleContainer(hitObject.Position);
+ addBubbleContainer(hitObject.Position, drawableOsuObject);
break;
//Stack leniency causes placement issues if this isn't handled as such.
case DrawableHitCircle hitCircle:
- addBubbleContainer(hitCircle.Position);
+ addBubbleContainer(hitCircle.Position, drawableOsuObject);
break;
case DrawableSpinnerTick:
@@ -99,19 +99,24 @@ namespace osu.Game.Rulesets.Osu.Mods
return;
default:
- addBubbleContainer(hitObject.Position);
+ addBubbleContainer(hitObject.Position, drawableOsuObject);
break;
}
+ }
- void addBubbleContainer(Vector2 position) => bubbleContainer.Add(new BubbleLifeTimeEntry
+ private void addBubbleContainer(Vector2 position, DrawableHitObject hitObject)
+ {
+ bubbleContainer.Add
+ (
+ new BubbleLifeTimeEntry
{
LifetimeStart = bubbleContainer.Time.Current,
- Colour = drawableOsuObject.AccentColour.Value,
+ Colour = hitObject.AccentColour.Value,
Position = position,
InitialSize = new Vector2(bubbleRadius),
MaxSize = maxSize,
FadeTime = bubbleFade,
- IsHit = drawableOsuObject.IsHit
+ IsHit = hitObject.IsHit
}
);
}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
index 38d90eb121..c8c4cd6a14 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMagnetised.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "No need to chase the circles – your cursor is a magnet!";
public override double ScoreMultiplier => 0.5;
- public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel) };
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModRelax), typeof(OsuModRepel), typeof(OsuModBubbles) };
[SettingSource("Attraction strength", "How strong the pull is.", 0)]
public BindableFloat AttractionStrength { get; } = new BindableFloat(0.5f)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
index 31a6b69d6b..28d459cedb 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModRepel.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override ModType Type => ModType.Fun;
public override LocalisableString Description => "Hit objects run away!";
public override double ScoreMultiplier => 1;
- public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised) };
+ public override Type[] IncompatibleMods => new[] { typeof(OsuModAutopilot), typeof(OsuModWiggle), typeof(OsuModTransform), typeof(ModAutoplay), typeof(OsuModMagnetised), typeof(OsuModBubbles) };
[SettingSource("Repulsion strength", "How strong the repulsion is.", 0)]
public BindableFloat RepulsionStrength { get; } = new BindableFloat(0.5f)
From ca84b885dcc6695cb7da3549757f7e6338bc37de Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 11 Jan 2023 17:51:41 +0100
Subject: [PATCH 008/476] Add more detail to bubbles
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 58 ++++++++++++++++-----
1 file changed, 45 insertions(+), 13 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 2e4d574148..f5e7e035b2 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -12,6 +12,7 @@ using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
+using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Pooling;
@@ -21,6 +22,7 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osuTK;
+using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -178,21 +180,38 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private partial class BubbleDrawable : CompositeDrawable
+ private partial class BubbleDrawable : CompositeDrawable, IHasAccentColour
{
+ public Color4 AccentColour { get; set; }
+
+ private Circle outerCircle = null!;
+ private Circle innerCircle = null!;
+
[BackgroundDependencyLoader]
private void load()
{
- InternalChild = new Circle
+ InternalChildren = new Drawable[]
{
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- EdgeEffect = new EdgeEffectParameters
+ outerCircle = new Circle
{
- Colour = Colour4.Black.Opacity(0.05f),
- Type = EdgeEffectType.Shadow,
- Radius = 5
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Masking = true,
+ MaskingSmoothness = 2,
+ BorderThickness = 0,
+ BorderColour = Colour4.Transparent,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Colour = Colour4.Black.Opacity(0.05f)
+ }
+ },
+ innerCircle = new Circle
+ {
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Scale = new Vector2(0.5f)
}
};
}
@@ -202,12 +221,25 @@ namespace osu.Game.Rulesets.Osu.Mods
Size = entry.InitialSize;
this
.ScaleTo(entry.MaxSize, entry.FadeTime * 6, Easing.OutSine)
- .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
- .Delay(entry.FadeTime)
- .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine)
.Then()
.ScaleTo(entry.MaxSize * 1.5f, entry.FadeTime, Easing.OutSine)
- .FadeTo(0, entry.FadeTime, Easing.OutQuint);
+ .FadeTo(0, entry.FadeTime, Easing.OutExpo);
+
+ animateCircles(entry);
+ }
+
+ private void animateCircles(BubbleLifeTimeEntry entry)
+ {
+ innerCircle.FadeColour(entry.IsHit ? entry.Colour.Darken(0.2f) : Colour4.Black)
+ .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, entry.FadeTime * 7);
+
+ innerCircle.FadeTo(0.5f, entry.FadeTime * 7, Easing.InExpo)
+ .ScaleTo(1.1f, entry.FadeTime * 7, Easing.InSine);
+
+ outerCircle
+ .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
+ .Delay(entry.FadeTime)
+ .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine);
}
}
From 7c81f1e75bb40981a55f16a3544d9521280bf49c Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Fri, 27 Jan 2023 11:21:11 +0100
Subject: [PATCH 009/476] Remove unnecessary BDL from bubble drawable
Improve animation duration formula
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 85 +++++++++------------
1 file changed, 38 insertions(+), 47 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index f5e7e035b2..6613d84e0e 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -12,7 +11,6 @@ using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
-using osu.Game.Graphics;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Pooling;
@@ -22,7 +20,6 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Mods
{
@@ -63,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
// Multiplying by 2 results in an initial size that is too large, hence 1.85 has been chosen
bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.85f);
- bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimeFadeIn * 2;
+ bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
drawableRuleset.Playfield.DisplayJudgements.Value = false;
@@ -125,8 +122,8 @@ namespace osu.Game.Rulesets.Osu.Mods
#region Pooled Bubble drawable
- //LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
- //Todo: find solution to bubbles rewinding in "groups"
+ // LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
+ // Todo: find solution to bubbles rewinding in "groups"
private sealed partial class BubbleContainer : PooledDrawableWithLifetimeContainer
{
protected override bool RemoveRewoundEntry => true;
@@ -166,8 +163,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private void apply(BubbleLifeTimeEntry? entry)
{
- if (entry == null)
- return;
+ if (entry == null) return;
ApplyTransformsAt(float.MinValue, true);
ClearTransforms(true);
@@ -180,38 +176,36 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
- private partial class BubbleDrawable : CompositeDrawable, IHasAccentColour
+ private partial class BubbleDrawable : CircularContainer
{
- public Color4 AccentColour { get; set; }
+ private readonly Circle innerCircle;
+ private readonly Box colourBox;
- private Circle outerCircle = null!;
- private Circle innerCircle = null!;
-
- [BackgroundDependencyLoader]
- private void load()
+ public BubbleDrawable()
{
- InternalChildren = new Drawable[]
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Masking = true;
+ MaskingSmoothness = 2;
+ BorderThickness = 0;
+ BorderColour = Colour4.Transparent;
+ EdgeEffect = new EdgeEffectParameters
{
- outerCircle = new Circle
- {
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Masking = true,
- MaskingSmoothness = 2,
- BorderThickness = 0,
- BorderColour = Colour4.Transparent,
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Shadow,
- Radius = 3,
- Colour = Colour4.Black.Opacity(0.05f)
- }
- },
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Colour = Colour4.Black.Opacity(0.05f)
+ };
+
+ Children = new Drawable[]
+ {
+ colourBox = new Box { RelativeSizeAxes = Axes.Both, },
innerCircle = new Circle
{
+ Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
- Scale = new Vector2(0.5f)
+ Size = new Vector2(0.5f),
}
};
}
@@ -219,27 +213,24 @@ namespace osu.Game.Rulesets.Osu.Mods
public void Animate(BubbleLifeTimeEntry entry)
{
Size = entry.InitialSize;
- this
- .ScaleTo(entry.MaxSize, entry.FadeTime * 6, Easing.OutSine)
+
+ this.ScaleTo(entry.MaxSize, getAnimationTime() * 0.8f, Easing.OutSine)
.Then()
- .ScaleTo(entry.MaxSize * 1.5f, entry.FadeTime, Easing.OutSine)
- .FadeTo(0, entry.FadeTime, Easing.OutExpo);
+ .ScaleTo(entry.MaxSize * 1.5f, getAnimationTime() * 0.2f, Easing.OutSine)
+ .FadeTo(0, getAnimationTime() * 0.2f, Easing.OutExpo);
- animateCircles(entry);
- }
+ colourBox.FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, getAnimationTime() * 0.1f, Easing.OutSine)
+ .Then()
+ .FadeColour(entry.IsHit ? entry.Colour.Darken(0.4f) : Colour4.Black, getAnimationTime() * 0.9f, Easing.OutSine);
- private void animateCircles(BubbleLifeTimeEntry entry)
- {
innerCircle.FadeColour(entry.IsHit ? entry.Colour.Darken(0.2f) : Colour4.Black)
- .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, entry.FadeTime * 7);
+ .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, getAnimationTime());
- innerCircle.FadeTo(0.5f, entry.FadeTime * 7, Easing.InExpo)
- .ScaleTo(1.1f, entry.FadeTime * 7, Easing.InSine);
+ innerCircle.FadeTo(0.5f, getAnimationTime(), Easing.InExpo)
+ .ScaleTo(2.2f, getAnimationTime(), Easing.InSine);
- outerCircle
- .FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, entry.FadeTime, Easing.OutSine)
- .Delay(entry.FadeTime)
- .FadeColour(entry.IsHit ? entry.Colour.Darken(.4f) : Colour4.Black, entry.FadeTime * 5, Easing.OutSine);
+ // The absolute length of the bubble's animation, can be used in fractions for animations of partial length
+ double getAnimationTime() => 2000 + 450 / (450 / entry.FadeTime);
}
}
From c3090dea5f7bea51e2662cd82fc292d65c56d7ca Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sat, 28 Jan 2023 00:30:30 +0100
Subject: [PATCH 010/476] Simplify animations
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 28 +++++++++++++--------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 6613d84e0e..479741b5b9 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -214,23 +214,29 @@ namespace osu.Game.Rulesets.Osu.Mods
{
Size = entry.InitialSize;
- this.ScaleTo(entry.MaxSize, getAnimationTime() * 0.8f, Easing.OutSine)
+ //We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
+ var colourDarker = entry.Colour.Darken(0.1f);
+
+ this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f, Easing.OutSine)
.Then()
- .ScaleTo(entry.MaxSize * 1.5f, getAnimationTime() * 0.2f, Easing.OutSine)
- .FadeTo(0, getAnimationTime() * 0.2f, Easing.OutExpo);
+ .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutSine)
+ .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutExpo);
- colourBox.FadeColour(entry.IsHit ? entry.Colour : Colour4.Black, getAnimationTime() * 0.1f, Easing.OutSine)
- .Then()
- .FadeColour(entry.IsHit ? entry.Colour.Darken(0.4f) : Colour4.Black, getAnimationTime() * 0.9f, Easing.OutSine);
+ innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutCubic);
- innerCircle.FadeColour(entry.IsHit ? entry.Colour.Darken(0.2f) : Colour4.Black)
- .FadeColour(entry.IsHit ? entry.Colour.Lighten(0.2f) : Colour4.Black, getAnimationTime());
+ if (!entry.IsHit)
+ {
+ colourBox.Colour = Colour4.Black;
+ innerCircle.Colour = Colour4.Black;
- innerCircle.FadeTo(0.5f, getAnimationTime(), Easing.InExpo)
- .ScaleTo(2.2f, getAnimationTime(), Easing.InSine);
+ return;
+ }
+
+ colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint);
+ innerCircle.FadeColour(colourDarker);
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationTime() => 2000 + 450 / (450 / entry.FadeTime);
+ double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.15f);
}
}
From 66da4c0288fd63d87fa7b4ea3547da39796e74e7 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sat, 28 Jan 2023 17:38:24 +0100
Subject: [PATCH 011/476] Add colouration to the sliders to better match the
vibrancy of the mod
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 27 +++++++++++++++------
1 file changed, 19 insertions(+), 8 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 479741b5b9..0101427f7a 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -16,6 +16,7 @@ using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Objects.Pooling;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
+using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
@@ -77,6 +78,12 @@ namespace osu.Game.Rulesets.Osu.Mods
private void applyBubbleState(DrawableHitObject drawableObject)
{
+ if (drawableObject is DrawableSlider slider)
+ {
+ slider.Body.OnSkinChanged += () => applySliderState(slider);
+ applySliderState(slider);
+ }
+
if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
OsuHitObject hitObject = drawableOsuObject.HitObject;
@@ -93,9 +100,9 @@ namespace osu.Game.Rulesets.Osu.Mods
addBubbleContainer(hitCircle.Position, drawableOsuObject);
break;
- case DrawableSpinnerTick:
case DrawableSlider:
- return;
+ case DrawableSpinnerTick:
+ break;
default:
addBubbleContainer(hitObject.Position, drawableOsuObject);
@@ -103,6 +110,9 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
+ private void applySliderState(DrawableSlider slider) =>
+ ((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
+
private void addBubbleContainer(Vector2 position, DrawableHitObject hitObject)
{
bubbleContainer.Add
@@ -217,12 +227,12 @@ namespace osu.Game.Rulesets.Osu.Mods
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
var colourDarker = entry.Colour.Darken(0.1f);
- this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f, Easing.OutSine)
+ this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f)
.Then()
- .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutSine)
- .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutExpo);
+ .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
+ .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutQuint);
- innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutCubic);
+ innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutQuint);
if (!entry.IsHit)
{
@@ -232,11 +242,12 @@ namespace osu.Game.Rulesets.Osu.Mods
return;
}
- colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint);
+ colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint
+ );
innerCircle.FadeColour(colourDarker);
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.15f);
+ double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.07f);
}
}
From 3bdf83bf44e63000d2a4c23c7467a1aa24b87724 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sat, 28 Jan 2023 22:44:57 +0100
Subject: [PATCH 012/476] Redo the drawable structure of bubbledrawable to run
and look better
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 50 ++++++++++-----------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 0101427f7a..2c90bfa399 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -5,6 +5,7 @@ using System;
using System.Linq;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Performance;
@@ -93,7 +94,7 @@ namespace osu.Game.Rulesets.Osu.Mods
//Needs to be done explicitly to avoid being handled by DrawableHitCircle below
case DrawableSliderHead:
addBubbleContainer(hitObject.Position, drawableOsuObject);
- break;
+ return;
//Stack leniency causes placement issues if this isn't handled as such.
case DrawableHitCircle hitCircle:
@@ -188,7 +189,6 @@ namespace osu.Game.Rulesets.Osu.Mods
private partial class BubbleDrawable : CircularContainer
{
- private readonly Circle innerCircle;
private readonly Box colourBox;
public BubbleDrawable()
@@ -196,55 +196,55 @@ namespace osu.Game.Rulesets.Osu.Mods
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
- Masking = true;
MaskingSmoothness = 2;
BorderThickness = 0;
- BorderColour = Colour4.Transparent;
+ BorderColour = Colour4.White;
+ Masking = true;
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Shadow,
Radius = 3,
Colour = Colour4.Black.Opacity(0.05f)
};
-
- Children = new Drawable[]
- {
- colourBox = new Box { RelativeSizeAxes = Axes.Both, },
- innerCircle = new Circle
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Size = new Vector2(0.5f),
- }
- };
+ Child = colourBox = new Box { RelativeSizeAxes = Axes.Both, };
}
public void Animate(BubbleLifeTimeEntry entry)
{
Size = entry.InitialSize;
+ BorderThickness = Width / 3.5f;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
- var colourDarker = entry.Colour.Darken(0.1f);
+ ColourInfo colourDarker = entry.Colour.Darken(0.1f);
+ // Main bubble scaling based on combo
this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f)
.Then()
+ // Pop at the end of the bubbles life time
.ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
- .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutQuint);
-
- innerCircle.ScaleTo(2f, getAnimationDuration() * 0.8f, Easing.OutQuint);
+ .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutCirc);
if (!entry.IsHit)
{
- colourBox.Colour = Colour4.Black;
- innerCircle.Colour = Colour4.Black;
+ Colour = Colour4.Black;
+ BorderColour = Colour4.Black;
return;
}
- colourBox.FadeColour(colourDarker, getAnimationDuration() * 0.2f, Easing.OutQuint
- );
- innerCircle.FadeColour(colourDarker);
+ colourBox.FadeColour(colourDarker);
+
+ this.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
+
+ // Ripple effect utilises the border to reduce drawable count
+ this.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
+
+ // Avoids transparency overlap issues during the bubble "pop"
+ .Then().Schedule(() =>
+ {
+ BorderThickness = 0;
+ BorderColour = Colour4.Transparent;
+ });
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.07f);
From f58534f60c76e4b0f9874eb91be336a49cb62035 Mon Sep 17 00:00:00 2001
From: Terochi
Date: Sun, 5 Feb 2023 16:35:11 +0100
Subject: [PATCH 013/476] Extended the length of replay at the end of map
---
osu.Game/Screens/Play/Player.cs | 88 +++++++++++++++++++--------------
1 file changed, 52 insertions(+), 36 deletions(-)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index bf7f38cdd3..fda6bdaa8f 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -613,6 +613,8 @@ namespace osu.Game.Screens.Play
// if an exit has been requested, cancel any pending completion (the user has shown intention to exit).
resultsDisplayDelegate?.Cancel();
+ beginScoreImport();
+
// The actual exit is performed if
// - the pause / fail dialog was not requested
// - the pause / fail dialog was requested but is already displayed (user showing intention to exit).
@@ -735,14 +737,9 @@ namespace osu.Game.Screens.Play
// is no chance that a user could return to the (already completed) Player instance from a child screen.
ValidForResume = false;
- // Ensure we are not writing to the replay any more, as we are about to consume and store the score.
- DrawableRuleset.SetRecordTarget(null);
-
if (!Configuration.ShowResults)
return;
- prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
-
bool storyboardHasOutro = DimmableStoryboard.ContentDisplayed && !DimmableStoryboard.HasStoryboardEnded.Value;
if (storyboardHasOutro)
@@ -756,6 +753,56 @@ namespace osu.Game.Screens.Play
progressToResults(true);
}
+ ///
+ /// Queue the results screen for display.
+ ///
+ ///
+ /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes .
+ ///
+ /// Whether a minimum delay () should be added before the screen is displayed.
+ private void progressToResults(bool withDelay)
+ {
+ resultsDisplayDelegate?.Cancel();
+
+ double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0;
+
+ resultsDisplayDelegate = new ScheduledDelegate(() =>
+ {
+ if (prepareScoreForDisplayTask == null)
+ {
+ beginScoreImport();
+ return;
+ }
+
+ if (!prepareScoreForDisplayTask.IsCompleted)
+ // If the asynchronous preparation has not completed, keep repeating this delegate.
+ return;
+
+ resultsDisplayDelegate?.Cancel();
+
+ if (!this.IsCurrentScreen())
+ // This player instance may already be in the process of exiting.
+ return;
+
+ this.Push(CreateResults(prepareScoreForDisplayTask.GetResultSafely()));
+ }, Time.Current + delay, 50);
+
+ Scheduler.Add(resultsDisplayDelegate);
+ }
+
+ private void beginScoreImport()
+ {
+ // We do not want to import the score in cases where we don't show results
+ bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
+ if (!canShowResults)
+ return;
+
+ // Ensure we are not writing to the replay any more, as we are about to consume and store the score.
+ DrawableRuleset.SetRecordTarget(null);
+
+ prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
+ }
+
///
/// Asynchronously run score preparation operations (database import, online submission etc.).
///
@@ -785,37 +832,6 @@ namespace osu.Game.Screens.Play
return scoreCopy.ScoreInfo;
}
- ///
- /// Queue the results screen for display.
- ///
- ///
- /// A final display will only occur once all work is completed in . This means that even after calling this method, the results screen will never be shown until ScoreProcessor.HasCompleted becomes .
- ///
- /// Whether a minimum delay () should be added before the screen is displayed.
- private void progressToResults(bool withDelay)
- {
- resultsDisplayDelegate?.Cancel();
-
- double delay = withDelay ? RESULTS_DISPLAY_DELAY : 0;
-
- resultsDisplayDelegate = new ScheduledDelegate(() =>
- {
- if (prepareScoreForDisplayTask?.IsCompleted != true)
- // If the asynchronous preparation has not completed, keep repeating this delegate.
- return;
-
- resultsDisplayDelegate?.Cancel();
-
- if (!this.IsCurrentScreen())
- // This player instance may already be in the process of exiting.
- return;
-
- this.Push(CreateResults(prepareScoreForDisplayTask.GetResultSafely()));
- }, Time.Current + delay, 50);
-
- Scheduler.Add(resultsDisplayDelegate);
- }
-
protected override bool OnScroll(ScrollEvent e)
{
// During pause, allow global volume adjust regardless of settings.
From 45981125860b331d5f5dbaa59966e6d354f2fd4c Mon Sep 17 00:00:00 2001
From: Cootz
Date: Sun, 5 Feb 2023 21:46:38 +0300
Subject: [PATCH 014/476] Add OriginalBeatmapHash to ScoreInfo. Update db
schema_version, migration
---
osu.Game/Beatmaps/BeatmapManager.cs | 8 ++++++++
osu.Game/Database/RealmAccess.cs | 15 +++++++++++++++
osu.Game/Scoring/ScoreInfo.cs | 2 ++
3 files changed, 25 insertions(+)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index ad56bbbc3a..e972f067ca 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -25,6 +26,7 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
+using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Utils;
@@ -454,6 +456,12 @@ namespace osu.Game.Beatmaps
if (transferCollections)
beatmapInfo.TransferCollectionReferences(r, oldMd5Hash);
+ //Unlinking all scores from this beatmap
+ r.All().Where(s => s.BeatmapInfoID == beatmapInfo.ID).ForEach(s => s.BeatmapInfo = new BeatmapInfo());
+
+ //Linking all the previos scores
+ r.All().Where(s => s.OriginalBeatmapHash == beatmapInfo.Hash).ForEach(s => s.BeatmapInfo = beatmapInfo);
+
ProcessBeatmap?.Invoke((liveBeatmapSet, false));
});
}
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 177c671bca..422ceb8af3 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -70,6 +70,7 @@ namespace osu.Game.Database
/// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo.
/// 24 2022-08-22 Added MaximumStatistics to ScoreInfo.
/// 25 2022-09-18 Remove skins to add with new naming.
+ /// 26 2023-02-05 Added OriginalBeatmapHash to ScoreInfo.
///
private const int schema_version = 25;
@@ -865,6 +866,20 @@ namespace osu.Game.Database
case 25:
// Remove the default skins so they can be added back by SkinManager with updated naming.
migration.NewRealm.RemoveRange(migration.NewRealm.All().Where(s => s.Protected));
+ break;
+ case 26:
+ // Adding origin beatmap hash property to ensure the score corresponds to the version of beatmap it should
+ // See: https://github.com/ppy/osu/issues/22062
+ string ScoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
+
+ var oldScoreInfos = migration.OldRealm.DynamicApi.All(ScoreInfoName);
+ var newScoreInfos = migration.NewRealm.All();
+
+ for (int i = 0; i < newScoreInfos.Count(); i++)
+ {
+ newScoreInfos.ElementAt(i).OriginalBeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
+ }
+
break;
}
}
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 1009474d89..2c029bbe68 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -66,6 +66,8 @@ namespace osu.Game.Scoring
[MapTo("MaximumStatistics")]
public string MaximumStatisticsJson { get; set; } = string.Empty;
+ public string OriginalBeatmapHash { get; set; } = string.Empty;
+
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{
Ruleset = ruleset ?? new RulesetInfo();
From d23e787bc1f341ae41c3fa5a21467d0c9f320973 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Sun, 5 Feb 2023 21:55:50 +0300
Subject: [PATCH 015/476] Update `schema_version`
---
osu.Game/Database/RealmAccess.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 422ceb8af3..6f85b3f1be 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -72,7 +72,7 @@ namespace osu.Game.Database
/// 25 2022-09-18 Remove skins to add with new naming.
/// 26 2023-02-05 Added OriginalBeatmapHash to ScoreInfo.
///
- private const int schema_version = 25;
+ private const int schema_version = 26;
///
/// Lock object which is held during sections, blocking realm retrieval during blocking periods.
From 4f23e096d76e9ab33140b77472dd4fa6247d9b0c Mon Sep 17 00:00:00 2001
From: Terochi
Date: Mon, 6 Feb 2023 07:59:37 +0100
Subject: [PATCH 016/476] Improved readability
---
osu.Game/Screens/Play/Player.cs | 27 ++++++++++++++++++++-------
1 file changed, 20 insertions(+), 7 deletions(-)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index fda6bdaa8f..443108cf34 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -613,6 +613,7 @@ namespace osu.Game.Screens.Play
// if an exit has been requested, cancel any pending completion (the user has shown intention to exit).
resultsDisplayDelegate?.Cancel();
+ // import current score if possible.
beginScoreImport();
// The actual exit is performed if
@@ -770,7 +771,11 @@ namespace osu.Game.Screens.Play
{
if (prepareScoreForDisplayTask == null)
{
- beginScoreImport();
+ // Try importing score since the task hasn't been invoked yet.
+ if (!beginScoreImport())
+ // If the task hasn't started, the score will never be imported.
+ resultsDisplayDelegate?.Cancel();
+
return;
}
@@ -790,17 +795,25 @@ namespace osu.Game.Screens.Play
Scheduler.Add(resultsDisplayDelegate);
}
- private void beginScoreImport()
+ ///
+ /// Ends replay recording and runs only when results can be shown
+ ///
+ ///
+ /// Whether the task has been invoked
+ ///
+ private bool beginScoreImport()
{
- // We do not want to import the score in cases where we don't show results
- bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
- if (!canShowResults)
- return;
-
// Ensure we are not writing to the replay any more, as we are about to consume and store the score.
DrawableRuleset.SetRecordTarget(null);
+ // We do not want to import the score in cases where we don't show results
+ bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
+ if (!canShowResults)
+ return false;
+
prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
+
+ return true;
}
///
From abcb564a74efeb3bb9e43ee1686f402297d416b5 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Mon, 6 Feb 2023 17:32:17 +0900
Subject: [PATCH 017/476] Code quality pass of `OsuModBubbles`
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 24 ++++++---------------
1 file changed, 6 insertions(+), 18 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 2c90bfa399..3606434042 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -29,15 +29,15 @@ namespace osu.Game.Rulesets.Osu.Mods
{
public override string Name => "Bubbles";
- public override string Acronym => "BB";
+ public override string Acronym => "BU";
- public override LocalisableString Description => "Dont let their popping distract you!";
+ public override LocalisableString Description => "Don't let their popping distract you!";
public override double ScoreMultiplier => 1;
public override ModType Type => ModType.Fun;
- // Compatibility with these seems potentially feasible in the future, blocked for now because they dont work as one would expect
+ // Compatibility with these seems potentially feasible in the future, blocked for now because they don't work as one would expect
public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
private PlayfieldAdjustmentContainer adjustmentContainer = null!;
@@ -87,26 +87,14 @@ namespace osu.Game.Rulesets.Osu.Mods
if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
- OsuHitObject hitObject = drawableOsuObject.HitObject;
-
switch (drawableOsuObject)
{
- //Needs to be done explicitly to avoid being handled by DrawableHitCircle below
- case DrawableSliderHead:
- addBubbleContainer(hitObject.Position, drawableOsuObject);
- return;
-
- //Stack leniency causes placement issues if this isn't handled as such.
- case DrawableHitCircle hitCircle:
- addBubbleContainer(hitCircle.Position, drawableOsuObject);
- break;
-
case DrawableSlider:
case DrawableSpinnerTick:
break;
default:
- addBubbleContainer(hitObject.Position, drawableOsuObject);
+ addBubbleForObject(drawableOsuObject);
break;
}
}
@@ -114,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private void applySliderState(DrawableSlider slider) =>
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
- private void addBubbleContainer(Vector2 position, DrawableHitObject hitObject)
+ private void addBubbleForObject(DrawableOsuHitObject hitObject)
{
bubbleContainer.Add
(
@@ -122,7 +110,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
LifetimeStart = bubbleContainer.Time.Current,
Colour = hitObject.AccentColour.Value,
- Position = position,
+ Position = hitObject.HitObject.Position,
InitialSize = new Vector2(bubbleRadius),
MaxSize = maxSize,
FadeTime = bubbleFade,
From 43f7665c9eabe7105bb1a7c1c2ace3784214d28f Mon Sep 17 00:00:00 2001
From: Terochi
Date: Mon, 6 Feb 2023 09:49:42 +0100
Subject: [PATCH 018/476] Improved readability again
---
osu.Game/Screens/Play/Player.cs | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 443108cf34..2f81b7154a 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -614,7 +614,7 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate?.Cancel();
// import current score if possible.
- beginScoreImport();
+ attemptScoreImport();
// The actual exit is performed if
// - the pause / fail dialog was not requested
@@ -772,8 +772,8 @@ namespace osu.Game.Screens.Play
if (prepareScoreForDisplayTask == null)
{
// Try importing score since the task hasn't been invoked yet.
- if (!beginScoreImport())
- // If the task hasn't started, the score will never be imported.
+ if (!attemptScoreImport())
+ // If attempt failed, trying again is unnecessary
resultsDisplayDelegate?.Cancel();
return;
@@ -796,12 +796,12 @@ namespace osu.Game.Screens.Play
}
///
- /// Ends replay recording and runs only when results can be shown
+ /// Attempts to run
///
///
- /// Whether the task has been invoked
+ /// Whether the attempt was successful
///
- private bool beginScoreImport()
+ private bool attemptScoreImport()
{
// Ensure we are not writing to the replay any more, as we are about to consume and store the score.
DrawableRuleset.SetRecordTarget(null);
From b00848e742d48ef08849d5115690909109c88de9 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Mon, 6 Feb 2023 13:58:41 +0300
Subject: [PATCH 019/476] Fix realm error. Apply `OriginalBeatmapHash` on
import
---
osu.Game/Beatmaps/BeatmapManager.cs | 6 ------
osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 1 +
2 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index e972f067ca..b46859cc59 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -456,12 +456,6 @@ namespace osu.Game.Beatmaps
if (transferCollections)
beatmapInfo.TransferCollectionReferences(r, oldMd5Hash);
- //Unlinking all scores from this beatmap
- r.All().Where(s => s.BeatmapInfoID == beatmapInfo.ID).ForEach(s => s.BeatmapInfo = new BeatmapInfo());
-
- //Linking all the previos scores
- r.All().Where(s => s.OriginalBeatmapHash == beatmapInfo.Hash).ForEach(s => s.BeatmapInfo = beatmapInfo);
-
ProcessBeatmap?.Invoke((liveBeatmapSet, false));
});
}
diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
index 6f0b0c62f8..4bd068ca0f 100644
--- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
+++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
@@ -123,6 +123,7 @@ namespace osu.Game.Scoring.Legacy
// before returning for database import, we must restore the database-sourced BeatmapInfo.
// if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
score.ScoreInfo.BeatmapInfo = workingBeatmap.BeatmapInfo;
+ score.ScoreInfo.OriginalBeatmapHash = workingBeatmap.BeatmapInfo.Hash;
return score;
}
From 2c7386db39d894cfa8ef335e7c58659399ed2e19 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Mon, 6 Feb 2023 15:14:14 +0300
Subject: [PATCH 020/476] FIx score appearing on `BeatmapLeaderboard` and
`TopLocalRank`
---
osu.Game/Screens/Play/Player.cs | 1 +
osu.Game/Screens/Select/Carousel/TopLocalRank.cs | 1 +
osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 1 +
3 files changed, 3 insertions(+)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 0d208e6d9b..7bd020db93 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -248,6 +248,7 @@ namespace osu.Game.Screens.Play
// ensure the score is in a consistent state with the current player.
Score.ScoreInfo.BeatmapInfo = Beatmap.Value.BeatmapInfo;
+ Score.ScoreInfo.OriginalBeatmapHash = Beatmap.Value.BeatmapInfo.Hash;
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods;
diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
index f1b773c831..3df72f7d3b 100644
--- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
+++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
@@ -65,6 +65,7 @@ namespace osu.Game.Screens.Select.Carousel
r.All()
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
+ + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2"
+ $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName),
localScoresChanged);
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 5c720c8491..3e90d2465b 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -191,6 +191,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scoreSubscription = realm.RegisterForNotifications(r =>
r.All().Filter($"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
+ + $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ $" AND {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1"
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
From f0d4b9f0ca339c79c74fba39f1d9a97de37f5f6e Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Mon, 6 Feb 2023 17:00:47 +0100
Subject: [PATCH 021/476] Add inline comment for colour border override
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 3606434042..41430bb323 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -99,6 +99,7 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
+ // Makes the slider border coloured on all skins
private void applySliderState(DrawableSlider slider) =>
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
From cb26601cb4be90a62d898d230a14ac9cb667ecc3 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 02:29:28 +0300
Subject: [PATCH 022/476] Fix test's score generation
---
osu.Game.Tests/Resources/TestResources.cs | 1 +
.../Visual/SongSelect/TestSceneBeatmapLeaderboard.cs | 10 ++++++++++
.../Visual/UserInterface/TestSceneDeleteLocalScore.cs | 1 +
3 files changed, 12 insertions(+)
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index adf28afc8e..f65d427649 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -176,6 +176,7 @@ namespace osu.Game.Tests.Resources
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
},
BeatmapInfo = beatmap,
+ OriginalBeatmapHash = beatmap.Hash,
Ruleset = beatmap.Ruleset,
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() },
TotalScore = 2845370,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index ef0ad6c25c..7a578230d9 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -210,6 +210,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
Ruleset = new OsuRuleset().RulesetInfo,
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
User = new APIUser
{
Id = 6602580,
@@ -226,6 +227,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-30),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
@@ -243,6 +245,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-70),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -261,6 +264,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMinutes(-40),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -279,6 +283,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -297,6 +302,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-25),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -315,6 +321,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-50),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -333,6 +340,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-72),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -351,6 +359,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMonths(-3),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -369,6 +378,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddYears(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index 7635c61867..14193b1ac8 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -94,6 +94,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
OnlineID = i,
BeatmapInfo = beatmapInfo,
+ OriginalBeatmapHash = beatmapInfo.Hash,
Accuracy = RNG.NextDouble(),
TotalScore = RNG.Next(1, 1000000),
MaxCombo = RNG.Next(1, 1000),
From 723f13af259da2e022a5c25b61d84b67c8ad75a9 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 02:43:27 +0300
Subject: [PATCH 023/476] Add summary for `OriginalBeatmapHash`
---
osu.Game/Scoring/ScoreInfo.cs | 3 +++
1 file changed, 3 insertions(+)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 2c029bbe68..7ad2d9203a 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -66,6 +66,9 @@ namespace osu.Game.Scoring
[MapTo("MaximumStatistics")]
public string MaximumStatisticsJson { get; set; } = string.Empty;
+ ///
+ /// Hash of the beatmap where it scored
+ ///
public string OriginalBeatmapHash { get; set; } = string.Empty;
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
From 1470ea0a311bec07ba3ba6525025939e51322a68 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 03:07:53 +0300
Subject: [PATCH 024/476] Remove unnecessary using directives
---
osu.Game/Beatmaps/BeatmapManager.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs
index b46859cc59..ad56bbbc3a 100644
--- a/osu.Game/Beatmaps/BeatmapManager.cs
+++ b/osu.Game/Beatmaps/BeatmapManager.cs
@@ -13,7 +13,6 @@ using System.Threading.Tasks;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;
-using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -26,7 +25,6 @@ using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
-using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Utils;
From a1ee3df453f46a271d7ba7450f791340119cc539 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 7 Feb 2023 03:16:25 +0300
Subject: [PATCH 025/476] Improve local variable naming
---
osu.Game/Database/RealmAccess.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 6f85b3f1be..1ef904fbc3 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -867,12 +867,13 @@ namespace osu.Game.Database
// Remove the default skins so they can be added back by SkinManager with updated naming.
migration.NewRealm.RemoveRange(migration.NewRealm.All().Where(s => s.Protected));
break;
+
case 26:
// Adding origin beatmap hash property to ensure the score corresponds to the version of beatmap it should
// See: https://github.com/ppy/osu/issues/22062
- string ScoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
+ string scoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
- var oldScoreInfos = migration.OldRealm.DynamicApi.All(ScoreInfoName);
+ var oldScoreInfos = migration.OldRealm.DynamicApi.All(scoreInfoName);
var newScoreInfos = migration.NewRealm.All();
for (int i = 0; i < newScoreInfos.Count(); i++)
From 957c9e7e276037c9c0db101f5e77cbaf3ceda5da Mon Sep 17 00:00:00 2001
From: Cootz <50776304+Cootz@users.noreply.github.com>
Date: Tue, 7 Feb 2023 11:23:39 +0300
Subject: [PATCH 026/476] Update osu.Game/Scoring/ScoreInfo.cs
Co-authored-by: Dean Herbert
---
osu.Game/Scoring/ScoreInfo.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 7ad2d9203a..2ea40df44d 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -67,9 +67,9 @@ namespace osu.Game.Scoring
public string MaximumStatisticsJson { get; set; } = string.Empty;
///
- /// Hash of the beatmap where it scored
+ /// The beatmap's at the point in time when the score was set.
///
- public string OriginalBeatmapHash { get; set; } = string.Empty;
+ public string BeatmapHash { get; set; } = string.Empty;
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{
From 7e127dafe21a89f5059f59de5cff7904f34e9783 Mon Sep 17 00:00:00 2001
From: PC
Date: Tue, 7 Feb 2023 11:52:47 +0300
Subject: [PATCH 027/476] Update reference
---
osu.Game.Tests/Resources/TestResources.cs | 2 +-
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 20 +++++++++----------
.../TestSceneDeleteLocalScore.cs | 2 +-
osu.Game/Database/RealmAccess.cs | 4 ++--
osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +-
osu.Game/Scoring/ScoreInfo.cs | 2 +-
osu.Game/Screens/Play/Player.cs | 2 +-
.../Screens/Select/Carousel/TopLocalRank.cs | 2 +-
.../Select/Leaderboards/BeatmapLeaderboard.cs | 2 +-
9 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index f65d427649..a2d81c0a75 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -176,7 +176,7 @@ namespace osu.Game.Tests.Resources
CoverUrl = "https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
},
BeatmapInfo = beatmap,
- OriginalBeatmapHash = beatmap.Hash,
+ BeatmapHash = beatmap.Hash,
Ruleset = beatmap.Ruleset,
Mods = new Mod[] { new TestModHardRock(), new TestModDoubleTime() },
TotalScore = 2845370,
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 7a578230d9..c4bca79480 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -210,7 +210,7 @@ namespace osu.Game.Tests.Visual.SongSelect
},
Ruleset = new OsuRuleset().RulesetInfo,
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
User = new APIUser
{
Id = 6602580,
@@ -227,7 +227,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-30),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
{
@@ -245,7 +245,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddSeconds(-70),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -264,7 +264,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMinutes(-40),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -283,7 +283,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -302,7 +302,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-25),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -321,7 +321,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-50),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -340,7 +340,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddHours(-72),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -359,7 +359,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddMonths(-3),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
@@ -378,7 +378,7 @@ namespace osu.Game.Tests.Visual.SongSelect
Date = DateTime.Now.AddYears(-2),
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Ruleset = new OsuRuleset().RulesetInfo,
User = new APIUser
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
index 14193b1ac8..529874b71e 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs
@@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.UserInterface
{
OnlineID = i,
BeatmapInfo = beatmapInfo,
- OriginalBeatmapHash = beatmapInfo.Hash,
+ BeatmapHash = beatmapInfo.Hash,
Accuracy = RNG.NextDouble(),
TotalScore = RNG.Next(1, 1000000),
MaxCombo = RNG.Next(1, 1000),
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 1ef904fbc3..b151fc6474 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -70,7 +70,7 @@ namespace osu.Game.Database
/// 23 2022-08-01 Added LastLocalUpdate to BeatmapInfo.
/// 24 2022-08-22 Added MaximumStatistics to ScoreInfo.
/// 25 2022-09-18 Remove skins to add with new naming.
- /// 26 2023-02-05 Added OriginalBeatmapHash to ScoreInfo.
+ /// 26 2023-02-05 Added BeatmapHash to ScoreInfo.
///
private const int schema_version = 26;
@@ -878,7 +878,7 @@ namespace osu.Game.Database
for (int i = 0; i < newScoreInfos.Count(); i++)
{
- newScoreInfos.ElementAt(i).OriginalBeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
+ newScoreInfos.ElementAt(i).BeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
}
break;
diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
index 4bd068ca0f..9b145ad56e 100644
--- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
+++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs
@@ -123,7 +123,7 @@ namespace osu.Game.Scoring.Legacy
// before returning for database import, we must restore the database-sourced BeatmapInfo.
// if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception.
score.ScoreInfo.BeatmapInfo = workingBeatmap.BeatmapInfo;
- score.ScoreInfo.OriginalBeatmapHash = workingBeatmap.BeatmapInfo.Hash;
+ score.ScoreInfo.BeatmapHash = workingBeatmap.BeatmapInfo.Hash;
return score;
}
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 2ea40df44d..62adcb9f94 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Scoring
public string MaximumStatisticsJson { get; set; } = string.Empty;
///
- /// The beatmap's at the point in time when the score was set.
+ /// The at the point in time when the score was set.
///
public string BeatmapHash { get; set; } = string.Empty;
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 7bd020db93..a3d8d3237c 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -248,7 +248,7 @@ namespace osu.Game.Screens.Play
// ensure the score is in a consistent state with the current player.
Score.ScoreInfo.BeatmapInfo = Beatmap.Value.BeatmapInfo;
- Score.ScoreInfo.OriginalBeatmapHash = Beatmap.Value.BeatmapInfo.Hash;
+ Score.ScoreInfo.BeatmapHash = Beatmap.Value.BeatmapInfo.Hash;
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods;
diff --git a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
index 3df72f7d3b..a57a8b0f27 100644
--- a/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
+++ b/osu.Game/Screens/Select/Carousel/TopLocalRank.cs
@@ -65,7 +65,7 @@ namespace osu.Game.Screens.Select.Carousel
r.All()
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
- + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ + $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2"
+ $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName),
localScoresChanged);
diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
index 3e90d2465b..2b40b9faf8 100644
--- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
+++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs
@@ -191,7 +191,7 @@ namespace osu.Game.Screens.Select.Leaderboards
scoreSubscription = realm.RegisterForNotifications(r =>
r.All().Filter($"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
- + $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.OriginalBeatmapHash)}"
+ + $" AND {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
+ $" AND {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1"
+ $" AND {nameof(ScoreInfo.DeletePending)} == false"
, beatmapInfo.ID, ruleset.Value.ShortName), localScoresChanged);
From 338d96534a2ad7b27d82eeeafb2c778fb67d0b67 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:01:54 +0300
Subject: [PATCH 028/476] Add leaderboard test on beatmap update
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index c4bca79480..13a24cd490 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -96,6 +96,37 @@ namespace osu.Game.Tests.Visual.SongSelect
checkCount(0);
}
+ [Test]
+ public void TestLocalScoresDisplayOnBeatmapEdit()
+ {
+ BeatmapInfo beatmapInfo = null!;
+
+ AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
+
+ AddStep(@"Set beatmap", () =>
+ {
+ beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
+ beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
+
+ leaderboard.BeatmapInfo = beatmapInfo;
+ });
+
+ clearScores();
+ checkCount(0);
+
+ loadMoreScores(() => beatmapInfo);
+ checkCount(10);
+
+ beatmapEdit(() => beatmapInfo);
+ checkCount(0);
+
+ loadMoreScores(() => beatmapInfo);
+ checkCount(10);
+
+ clearScores();
+ checkCount(0);
+ }
+
[Test]
public void TestGlobalScoresDisplay()
{
@@ -123,6 +154,21 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"None selected", () => leaderboard.SetErrorState(LeaderboardState.NoneSelected));
}
+ private void beatmapEdit(Func beatmapInfo)
+ {
+ AddStep(@"Update beatmap via BeatmapManager", () =>
+ {
+ BeatmapInfo info = beatmapInfo();
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(info).Beatmap;
+
+ beatmap.Difficulty.ApproachRate = 11;
+ beatmap.Difficulty.DrainRate = 11;
+ beatmap.Difficulty.OverallDifficulty = 11;
+
+ beatmapManager.Save(info, beatmap);
+ });
+ }
+
private void showPersonalBestWithNullPosition()
{
leaderboard.SetScores(leaderboard.Scores, new ScoreInfo
From 391af2791b875a9928bba1d92dbcbae2128c0dd0 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:23:42 +0300
Subject: [PATCH 029/476] Fix CSharpWarnings::CS1574,CS1584,CS1581,CS1580
---
osu.Game/Scoring/ScoreInfo.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 62adcb9f94..8c912ef32a 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Scoring
public string MaximumStatisticsJson { get; set; } = string.Empty;
///
- /// The at the point in time when the score was set.
+ /// The .Hash at the point in time when the score was set.
///
public string BeatmapHash { get; set; } = string.Empty;
From 6bf56aff73e07b7cd92241b251ae0ea0d9787b99 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:40:20 +0300
Subject: [PATCH 030/476] Add warning for `ScoreInfo`
---
osu.Game/Scoring/ScoreInfo.cs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 8c912ef32a..c57e06bee5 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -22,6 +22,13 @@ using Realms;
namespace osu.Game.Scoring
{
+
+ ///
+ /// Store information about the score
+ ///
+ ///
+ /// If you work on inporting/adding score please ensure you provide both BeatmapInfo and BeatmapHash
+ ///
[ExcludeFromDynamicCompile]
[MapTo("Score")]
public class ScoreInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable, IScoreInfo
From ab7c9a200bdcc7804927ca68b9c59da58d22d49f Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:42:06 +0300
Subject: [PATCH 031/476] Fix a typo
---
osu.Game/Scoring/ScoreInfo.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index c57e06bee5..85452ede17 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Scoring
/// Store information about the score
///
///
- /// If you work on inporting/adding score please ensure you provide both BeatmapInfo and BeatmapHash
+ /// Warning: If you work on importing/adding score please ensure you provide both BeatmapInfo and BeatmapHash
///
[ExcludeFromDynamicCompile]
[MapTo("Score")]
From 4ba915268c5e0a34824d2a03cb501a12574707a4 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:46:47 +0300
Subject: [PATCH 032/476] Change a comment into `RealmAccess`
---
osu.Game/Database/RealmAccess.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index b151fc6474..861a74e163 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -869,7 +869,7 @@ namespace osu.Game.Database
break;
case 26:
- // Adding origin beatmap hash property to ensure the score corresponds to the version of beatmap it should
+ // Add ScoreInfo.BeatmapHash property to ensure the score corresponds to the version of beatmap it should
// See: https://github.com/ppy/osu/issues/22062
string scoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
From 086b3eb542348048da062fde8234239e8d7d3ef6 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 8 Feb 2023 05:50:52 +0300
Subject: [PATCH 033/476] Fix minor formating issues
---
osu.Game/Scoring/ScoreInfo.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 85452ede17..d2ec4ebd5f 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -22,10 +22,9 @@ using Realms;
namespace osu.Game.Scoring
{
-
///
/// Store information about the score
- ///
+ ///
///
/// Warning: If you work on importing/adding score please ensure you provide both BeatmapInfo and BeatmapHash
///
From 5c113ddb030445c5099fdd2334d6b2608f5851ef Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 14:20:58 +0900
Subject: [PATCH 034/476] Reword xmldoc to read better
---
osu.Game/Scoring/ScoreInfo.cs | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index d2ec4ebd5f..6213c65c75 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -23,11 +23,8 @@ using Realms;
namespace osu.Game.Scoring
{
///
- /// Store information about the score
+ /// A realm model containing metadata for a single score.
///
- ///
- /// Warning: If you work on importing/adding score please ensure you provide both BeatmapInfo and BeatmapHash
- ///
[ExcludeFromDynamicCompile]
[MapTo("Score")]
public class ScoreInfo : RealmObject, IHasGuidPrimaryKey, IHasRealmFiles, ISoftDelete, IEquatable, IScoreInfo
@@ -35,8 +32,19 @@ namespace osu.Game.Scoring
[PrimaryKey]
public Guid ID { get; set; }
+ ///
+ /// The this score was made against.
+ ///
+ ///
+ /// When setting this, make sure to also set to allow relational consistency when a beatmap is potentially changed.
+ ///
public BeatmapInfo BeatmapInfo { get; set; } = null!;
+ ///
+ /// The at the point in time when the score was set.
+ ///
+ public string BeatmapHash { get; set; } = string.Empty;
+
public RulesetInfo Ruleset { get; set; } = null!;
public IList Files { get; } = null!;
@@ -72,11 +80,6 @@ namespace osu.Game.Scoring
[MapTo("MaximumStatistics")]
public string MaximumStatisticsJson { get; set; } = string.Empty;
- ///
- /// The .Hash at the point in time when the score was set.
- ///
- public string BeatmapHash { get; set; } = string.Empty;
-
public ScoreInfo(BeatmapInfo? beatmap = null, RulesetInfo? ruleset = null, RealmUser? realmUser = null)
{
Ruleset = ruleset ?? new RulesetInfo();
From c50ea89bc99f3dc142e85ecec3bf2504d3fd5f32 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 14:24:06 +0900
Subject: [PATCH 035/476] Simplify migration to not rely on old/dynamic schema
---
osu.Game/Database/RealmAccess.cs | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs
index 861a74e163..831e328439 100644
--- a/osu.Game/Database/RealmAccess.cs
+++ b/osu.Game/Database/RealmAccess.cs
@@ -869,17 +869,11 @@ namespace osu.Game.Database
break;
case 26:
- // Add ScoreInfo.BeatmapHash property to ensure the score corresponds to the version of beatmap it should
- // See: https://github.com/ppy/osu/issues/22062
- string scoreInfoName = getMappedOrOriginalName(typeof(ScoreInfo));
+ // Add ScoreInfo.BeatmapHash property to ensure scores correspond to the correct version of beatmap.
+ var scores = migration.NewRealm.All();
- var oldScoreInfos = migration.OldRealm.DynamicApi.All(scoreInfoName);
- var newScoreInfos = migration.NewRealm.All();
-
- for (int i = 0; i < newScoreInfos.Count(); i++)
- {
- newScoreInfos.ElementAt(i).BeatmapHash = oldScoreInfos.ElementAt(i).BeatmapInfo.Hash;
- }
+ foreach (var score in scores)
+ score.BeatmapHash = score.BeatmapInfo.Hash;
break;
}
From c7eec371f52dd403a0bfaeea6f645d4a56dd3857 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:22:17 +0900
Subject: [PATCH 036/476] Clean up tests somewhat
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 41 ++++++++-----------
1 file changed, 18 insertions(+), 23 deletions(-)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 13a24cd490..83bb58804d 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -86,10 +86,10 @@ namespace osu.Game.Tests.Visual.SongSelect
clearScores();
checkCount(0);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(10);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(20);
clearScores();
@@ -114,13 +114,23 @@ namespace osu.Game.Tests.Visual.SongSelect
clearScores();
checkCount(0);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(10);
- beatmapEdit(() => beatmapInfo);
+ AddStep(@"Save beatmap with changes", () =>
+ {
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
+
+ beatmap.Difficulty.ApproachRate = 11;
+ beatmap.Difficulty.DrainRate = 11;
+ beatmap.Difficulty.OverallDifficulty = 11;
+
+ beatmapManager.Save(beatmapInfo, beatmap);
+ });
+
checkCount(0);
- loadMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
checkCount(10);
clearScores();
@@ -154,21 +164,6 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep(@"None selected", () => leaderboard.SetErrorState(LeaderboardState.NoneSelected));
}
- private void beatmapEdit(Func beatmapInfo)
- {
- AddStep(@"Update beatmap via BeatmapManager", () =>
- {
- BeatmapInfo info = beatmapInfo();
- IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(info).Beatmap;
-
- beatmap.Difficulty.ApproachRate = 11;
- beatmap.Difficulty.DrainRate = 11;
- beatmap.Difficulty.OverallDifficulty = 11;
-
- beatmapManager.Save(info, beatmap);
- });
- }
-
private void showPersonalBestWithNullPosition()
{
leaderboard.SetScores(leaderboard.Scores, new ScoreInfo
@@ -208,9 +203,9 @@ namespace osu.Game.Tests.Visual.SongSelect
});
}
- private void loadMoreScores(Func beatmapInfo)
+ private void importMoreScores(Func beatmapInfo)
{
- AddStep(@"Load new scores via manager", () =>
+ AddStep(@"Import new scores", () =>
{
foreach (var score in generateSampleScores(beatmapInfo()))
scoreManager.Import(score);
@@ -223,7 +218,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}
private void checkCount(int expected) =>
- AddUntilStep("Correct count displayed", () => leaderboard.ChildrenOfType().Count() == expected);
+ AddUntilStep($"{expected} scores displayed", () => leaderboard.ChildrenOfType().Count(), () => Is.EqualTo(expected));
private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmapInfo)
{
From d4d985ba0f0378d3c93a71b17e5cfcb793a7b41b Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:34:46 +0900
Subject: [PATCH 037/476] Improve test to also check that reverting hash
restores old scores
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 31 ++++++++++++++-----
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 83bb58804d..01397563fd 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -100,10 +100,11 @@ namespace osu.Game.Tests.Visual.SongSelect
public void TestLocalScoresDisplayOnBeatmapEdit()
{
BeatmapInfo beatmapInfo = null!;
+ string originalHash = string.Empty;
AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local);
- AddStep(@"Set beatmap", () =>
+ AddStep(@"Import beatmap", () =>
{
beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).WaitSafely();
beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First();
@@ -114,23 +115,39 @@ namespace osu.Game.Tests.Visual.SongSelect
clearScores();
checkCount(0);
+ AddStep(@"Perform initial save to guarantee stable hash", () =>
+ {
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
+ beatmapManager.Save(beatmapInfo, beatmap);
+
+ originalHash = beatmapInfo.Hash;
+ });
+
importMoreScores(() => beatmapInfo);
checkCount(10);
- AddStep(@"Save beatmap with changes", () =>
+ AddStep(@"Save with changes", () =>
{
IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
-
- beatmap.Difficulty.ApproachRate = 11;
- beatmap.Difficulty.DrainRate = 11;
- beatmap.Difficulty.OverallDifficulty = 11;
-
+ beatmap.Difficulty.ApproachRate = 12;
beatmapManager.Save(beatmapInfo, beatmap);
});
+ AddAssert("Hash changed", () => beatmapInfo.Hash, () => Is.Not.EqualTo(originalHash));
checkCount(0);
importMoreScores(() => beatmapInfo);
+ importMoreScores(() => beatmapInfo);
+ checkCount(20);
+
+ AddStep(@"Revert changes", () =>
+ {
+ IBeatmap beatmap = beatmapManager.GetWorkingBeatmap(beatmapInfo).Beatmap;
+ beatmap.Difficulty.ApproachRate = 8;
+ beatmapManager.Save(beatmapInfo, beatmap);
+ });
+
+ AddAssert("Hash restored", () => beatmapInfo.Hash, () => Is.EqualTo(originalHash));
checkCount(10);
clearScores();
From 38031fdf2327cb50705cd14fa55c4cb1cb058a9d Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:38:07 +0900
Subject: [PATCH 038/476] Add test coverage of stores stored in database as
well
---
.../SongSelect/TestSceneBeatmapLeaderboard.cs | 31 ++++++++++++-------
1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
index 01397563fd..c234cc8a9c 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs
@@ -84,16 +84,16 @@ namespace osu.Game.Tests.Visual.SongSelect
});
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
importMoreScores(() => beatmapInfo);
- checkCount(10);
+ checkDisplayedCount(10);
importMoreScores(() => beatmapInfo);
- checkCount(20);
+ checkDisplayedCount(20);
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
}
[Test]
@@ -113,7 +113,7 @@ namespace osu.Game.Tests.Visual.SongSelect
});
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
AddStep(@"Perform initial save to guarantee stable hash", () =>
{
@@ -124,7 +124,9 @@ namespace osu.Game.Tests.Visual.SongSelect
});
importMoreScores(() => beatmapInfo);
- checkCount(10);
+
+ checkDisplayedCount(10);
+ checkStoredCount(10);
AddStep(@"Save with changes", () =>
{
@@ -134,11 +136,13 @@ namespace osu.Game.Tests.Visual.SongSelect
});
AddAssert("Hash changed", () => beatmapInfo.Hash, () => Is.Not.EqualTo(originalHash));
- checkCount(0);
+ checkDisplayedCount(0);
+ checkStoredCount(10);
importMoreScores(() => beatmapInfo);
importMoreScores(() => beatmapInfo);
- checkCount(20);
+ checkDisplayedCount(20);
+ checkStoredCount(30);
AddStep(@"Revert changes", () =>
{
@@ -148,10 +152,12 @@ namespace osu.Game.Tests.Visual.SongSelect
});
AddAssert("Hash restored", () => beatmapInfo.Hash, () => Is.EqualTo(originalHash));
- checkCount(10);
+ checkDisplayedCount(10);
+ checkStoredCount(30);
clearScores();
- checkCount(0);
+ checkDisplayedCount(0);
+ checkStoredCount(0);
}
[Test]
@@ -234,9 +240,12 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("Clear all scores", () => scoreManager.Delete());
}
- private void checkCount(int expected) =>
+ private void checkDisplayedCount(int expected) =>
AddUntilStep($"{expected} scores displayed", () => leaderboard.ChildrenOfType().Count(), () => Is.EqualTo(expected));
+ private void checkStoredCount(int expected) =>
+ AddUntilStep($"Total scores stored is {expected}", () => Realm.Run(r => r.All().Count(s => !s.DeletePending)), () => Is.EqualTo(expected));
+
private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmapInfo)
{
return new[]
From 4fdba880b1efc2dcb49a2f3c64585f2e896a64ba Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Wed, 8 Feb 2023 15:39:18 +0900
Subject: [PATCH 039/476] Fix xmldoc reference fail at CI
---
osu.Game/Scoring/ScoreInfo.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index 6213c65c75..02c7acf350 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -41,7 +41,7 @@ namespace osu.Game.Scoring
public BeatmapInfo BeatmapInfo { get; set; } = null!;
///
- /// The at the point in time when the score was set.
+ /// The at the point in time when the score was set.
///
public string BeatmapHash { get; set; } = string.Empty;
From 5e0c4aa904f28435bb2ffad3967f2f4fe2b08802 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 8 Feb 2023 11:12:14 +0100
Subject: [PATCH 040/476] Refactor pooling for bubbles, tweak the animations a
tad, add some clarifying comments
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 231 ++++++++++----------
1 file changed, 114 insertions(+), 117 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 41430bb323..8cf9c619d7 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -8,13 +8,11 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
-using osu.Framework.Graphics.Performance;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
-using osu.Game.Rulesets.Objects.Pooling;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Skinning.Default;
@@ -41,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
private PlayfieldAdjustmentContainer adjustmentContainer = null!;
- private BubbleContainer bubbleContainer = null!;
+ private Container bubbleContainer = null!;
private readonly Bindable currentCombo = new BindableInt();
@@ -49,6 +47,10 @@ namespace osu.Game.Rulesets.Osu.Mods
private float bubbleRadius;
private double bubbleFade;
+ private readonly DrawablePool bubblePool = new DrawablePool(100);
+
+ private DrawableOsuHitObject lastJudgedHitobject = null!;
+
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
@@ -56,6 +58,63 @@ namespace osu.Game.Rulesets.Osu.Mods
currentCombo.BindTo(scoreProcessor.Combo);
currentCombo.BindValueChanged(combo =>
maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
+
+ scoreProcessor.NewJudgement += result =>
+ {
+ if (result.HitObject is not OsuHitObject osuHitObject) return;
+
+ DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitobject;
+
+ switch (result.HitObject)
+ {
+ case Slider:
+ case SpinnerTick:
+ break;
+
+ default:
+ addBubble();
+ break;
+ }
+
+ void addBubble()
+ {
+ BubbleDrawable bubble = bubblePool.Get();
+ bubble.Info = new BubbleInfo
+ {
+ InitialSize = new Vector2(bubbleRadius),
+ MaxSize = maxSize,
+ Position = getPosition(),
+ FadeTime = bubbleFade,
+ Colour = drawableOsuHitObject.AccentColour.Value,
+ IsHit = drawableOsuHitObject.IsHit,
+ };
+ bubbleContainer.Add(bubble);
+ }
+
+ Vector2 getPosition()
+ {
+ switch (drawableOsuHitObject)
+ {
+ // SliderHeads are derived from HitCircles,
+ // so we must handle them before to avoid them using the wrong positioning logic
+ case DrawableSliderHead:
+ return osuHitObject.Position;
+
+ // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
+ case DrawableHitCircle:
+ return drawableOsuHitObject.Position;
+
+ default:
+ return osuHitObject.Position;
+ }
+ }
+ };
+
+ scoreProcessor.JudgementReverted += _ =>
+ {
+ bubbleContainer.LastOrDefault()?.FinishTransforms();
+ bubbleContainer.LastOrDefault()?.Expire();
+ };
}
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
@@ -69,178 +128,116 @@ namespace osu.Game.Rulesets.Osu.Mods
adjustmentContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
- adjustmentContainer.Add(bubbleContainer = new BubbleContainer());
+ adjustmentContainer.Add(bubbleContainer = new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ });
drawableRuleset.KeyBindingInputManager.Add(adjustmentContainer);
}
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
-
protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
private void applyBubbleState(DrawableHitObject drawableObject)
{
+ DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)drawableObject;
+
if (drawableObject is DrawableSlider slider)
{
slider.Body.OnSkinChanged += () => applySliderState(slider);
applySliderState(slider);
}
- if (drawableObject is not DrawableOsuHitObject drawableOsuObject || !drawableObject.Judged) return;
+ if (osuHitObject == lastJudgedHitobject || !osuHitObject.Judged) return;
- switch (drawableOsuObject)
+ switch (osuHitObject)
{
case DrawableSlider:
case DrawableSpinnerTick:
break;
default:
- addBubbleForObject(drawableOsuObject);
+ lastJudgedHitobject = osuHitObject;
break;
}
}
- // Makes the slider border coloured on all skins
+ // Makes the slider border coloured on all skins (for aesthetics)
private void applySliderState(DrawableSlider slider) =>
((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
- private void addBubbleForObject(DrawableOsuHitObject hitObject)
- {
- bubbleContainer.Add
- (
- new BubbleLifeTimeEntry
- {
- LifetimeStart = bubbleContainer.Time.Current,
- Colour = hitObject.AccentColour.Value,
- Position = hitObject.HitObject.Position,
- InitialSize = new Vector2(bubbleRadius),
- MaxSize = maxSize,
- FadeTime = bubbleFade,
- IsHit = hitObject.IsHit
- }
- );
- }
-
#region Pooled Bubble drawable
- // LifetimeEntry flow is necessary to allow for correct rewind behaviour, can probably be made generic later if more mods are made requiring it
- // Todo: find solution to bubbles rewinding in "groups"
- private sealed partial class BubbleContainer : PooledDrawableWithLifetimeContainer
- {
- protected override bool RemoveRewoundEntry => true;
-
- private readonly DrawablePool pool;
-
- public BubbleContainer()
- {
- RelativeSizeAxes = Axes.Both;
- AddInternal(pool = new DrawablePool(10, 1000));
- }
-
- protected override BubbleObject GetDrawable(BubbleLifeTimeEntry entry) => pool.Get(d => d.Apply(entry));
- }
-
- private sealed partial class BubbleObject : PoolableDrawableWithLifetime
- {
- private readonly BubbleDrawable bubbleDrawable;
-
- public BubbleObject()
- {
- InternalChild = bubbleDrawable = new BubbleDrawable();
- }
-
- protected override void OnApply(BubbleLifeTimeEntry entry)
- {
- base.OnApply(entry);
- if (IsLoaded)
- apply(entry);
- }
-
- protected override void LoadComplete()
- {
- base.LoadComplete();
- apply(Entry);
- }
-
- private void apply(BubbleLifeTimeEntry? entry)
- {
- if (entry == null) return;
-
- ApplyTransformsAt(float.MinValue, true);
- ClearTransforms(true);
-
- Position = entry.Position;
-
- bubbleDrawable.Animate(entry);
-
- LifetimeEnd = bubbleDrawable.LatestTransformEndTime;
- }
- }
-
- private partial class BubbleDrawable : CircularContainer
+ private partial class BubbleDrawable : PoolableDrawable
{
private readonly Box colourBox;
+ private readonly CircularContainer content;
+
+ public BubbleInfo Info { get; set; }
public BubbleDrawable()
{
- Anchor = Anchor.Centre;
Origin = Anchor.Centre;
-
- MaskingSmoothness = 2;
- BorderThickness = 0;
- BorderColour = Colour4.White;
- Masking = true;
- EdgeEffect = new EdgeEffectParameters
+ InternalChild = content = new CircularContainer
{
- Type = EdgeEffectType.Shadow,
- Radius = 3,
- Colour = Colour4.Black.Opacity(0.05f)
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ MaskingSmoothness = 2,
+ BorderThickness = 0,
+ BorderColour = Colour4.White,
+ Masking = true,
+ EdgeEffect = new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Shadow,
+ Radius = 3,
+ Colour = Colour4.Black.Opacity(0.05f),
+ },
+ Child = colourBox = new Box { RelativeSizeAxes = Axes.Both, }
};
- Child = colourBox = new Box { RelativeSizeAxes = Axes.Both, };
}
- public void Animate(BubbleLifeTimeEntry entry)
+ protected override void PrepareForUse()
{
- Size = entry.InitialSize;
- BorderThickness = Width / 3.5f;
+ Alpha = 1;
+ Colour = Colour4.White;
+ Scale = new Vector2(1);
+ Position = Info.Position;
+ Size = Info.InitialSize;
+ content.BorderThickness = Info.InitialSize.X / 3.5f;
+ content.BorderColour = Colour4.White;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
- ColourInfo colourDarker = entry.Colour.Darken(0.1f);
+ ColourInfo colourDarker = Info.Colour.Darken(0.1f);
// Main bubble scaling based on combo
- this.ScaleTo(entry.MaxSize, getAnimationDuration() * 0.8f)
+ this.ScaleTo(Info.MaxSize, getAnimationDuration() * 0.8f)
.Then()
// Pop at the end of the bubbles life time
- .ScaleTo(entry.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
- .FadeTo(0, getAnimationDuration() * 0.2f, Easing.OutCirc);
+ .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
+ .FadeOutFromOne(getAnimationDuration() * 0.2f, Easing.OutCirc).Expire();
- if (!entry.IsHit)
+ if (Info.IsHit)
{
- Colour = Colour4.Black;
- BorderColour = Colour4.Black;
+ colourBox.FadeColour(colourDarker);
+
+ content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
+ // Ripple effect utilises the border to reduce drawable count
+ content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
+ // Avoids transparency overlap issues during the bubble "pop"
+ .Then().Schedule(() => content.BorderThickness = 0);
return;
}
- colourBox.FadeColour(colourDarker);
-
- this.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
-
- // Ripple effect utilises the border to reduce drawable count
- this.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
-
- // Avoids transparency overlap issues during the bubble "pop"
- .Then().Schedule(() =>
- {
- BorderThickness = 0;
- BorderColour = Colour4.Transparent;
- });
+ Colour = Colour4.Black;
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration() => 1700 + Math.Pow(entry.FadeTime, 1.07f);
+ double getAnimationDuration() => 1700 + Math.Pow(Info.FadeTime, 1.07f);
}
}
- private class BubbleLifeTimeEntry : LifetimeEntry
+ private struct BubbleInfo
{
public Vector2 InitialSize { get; set; }
From 6ff6e06a69256987d7a409a154c021df9988df30 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Sun, 12 Feb 2023 11:37:07 +0100
Subject: [PATCH 041/476] Simplify bubble container structure, modify some
comments
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 8cf9c619d7..3e3fce5c27 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -38,8 +38,7 @@ namespace osu.Game.Rulesets.Osu.Mods
// Compatibility with these seems potentially feasible in the future, blocked for now because they don't work as one would expect
public override Type[] IncompatibleMods => new[] { typeof(OsuModBarrelRoll), typeof(OsuModMagnetised), typeof(OsuModRepel) };
- private PlayfieldAdjustmentContainer adjustmentContainer = null!;
- private Container bubbleContainer = null!;
+ private PlayfieldAdjustmentContainer bubbleContainer = null!;
private readonly Bindable currentCombo = new BindableInt();
@@ -119,20 +118,17 @@ namespace osu.Game.Rulesets.Osu.Mods
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
- // Multiplying by 2 results in an initial size that is too large, hence 1.85 has been chosen
- bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.85f);
+ // Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
+ // Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
+ bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
drawableRuleset.Playfield.DisplayJudgements.Value = false;
- adjustmentContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
+ bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
- adjustmentContainer.Add(bubbleContainer = new Container
- {
- RelativeSizeAxes = Axes.Both,
- });
- drawableRuleset.KeyBindingInputManager.Add(adjustmentContainer);
+ drawableRuleset.KeyBindingInputManager.Add(bubbleContainer);
}
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
From 74a58fb674945a5ec82f20ca2bffff91b6de776c Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 01:24:27 +0000
Subject: [PATCH 042/476] refactor: separate things in KeyCounter
To implement different different sources of input for KeyCounter, it
is now possible to create a Trigger class (to inherit) instead of
inheriting KeyCounter. This eases the creation of more input sources
(like for tests) while allowing to implement different UI variants.
That way, if another variant of the key counter needs to implemented
(for whathever reason), this can be done by only inheriting KeyCounter
and changing how things are arranged visually.
---
osu.Game/Rulesets/UI/RulesetInputManager.cs | 9 +-
osu.Game/Screens/Play/DefaultKeyCounter.cs | 105 +++++++++++++
osu.Game/Screens/Play/KeyCounter.cs | 157 +++++++-------------
osu.Game/Screens/Play/KeyCounterAction.cs | 10 +-
osu.Game/Screens/Play/KeyCounterKeyboard.cs | 11 +-
osu.Game/Screens/Play/KeyCounterMouse.cs | 11 +-
6 files changed, 177 insertions(+), 126 deletions(-)
create mode 100644 osu.Game/Screens/Play/DefaultKeyCounter.cs
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index a5e442b7de..0fa1f0b332 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.UI
.Select(b => b.GetAction())
.Distinct()
.OrderBy(action => action)
- .Select(action => new KeyCounterAction(action)));
+ .Select(action => keyCounter.CreateKeyCounter(new KeyCounterAction(action))));
}
private partial class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler
@@ -176,11 +176,14 @@ namespace osu.Game.Rulesets.UI
{
}
- public bool OnPressed(KeyBindingPressEvent e) => Target.Children.OfType>().Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
+ public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.CounterTrigger is KeyCounterAction)
+ .Select(c => (KeyCounterAction)c.CounterTrigger)
+ .Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
public void OnReleased(KeyBindingReleaseEvent e)
{
- foreach (var c in Target.Children.OfType>())
+ foreach (var c
+ in Target.Children.Where(c => c.CounterTrigger is KeyCounterAction).Select(c => (KeyCounterAction)c.CounterTrigger))
c.OnReleased(e.Action, Clock.Rate >= 0);
}
}
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
new file mode 100644
index 0000000000..dcb425ae1d
--- /dev/null
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -0,0 +1,105 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class DefaultKeyCounter : KeyCounter
+ {
+ private Sprite buttonSprite = null!;
+ private Sprite glowSprite = null!;
+ private Container textLayer = null!;
+ private SpriteText countSpriteText = null!;
+
+ //further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor
+ public Color4 KeyDownTextColor { get; set; } = Color4.DarkGray;
+ public Color4 KeyUpTextColor { get; set; } = Color4.White;
+ public double FadeTime { get; set; }
+
+ public DefaultKeyCounter(Trigger trigger)
+ : base(trigger)
+ {
+ }
+
+ [BackgroundDependencyLoader(true)]
+ private void load(TextureStore textures)
+ {
+ Children = new Drawable[]
+ {
+ buttonSprite = new Sprite
+ {
+ Texture = textures.Get(@"KeyCounter/key-up"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ },
+ glowSprite = new Sprite
+ {
+ Texture = textures.Get(@"KeyCounter/key-glow"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Alpha = 0
+ },
+ textLayer = new Container
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new OsuSpriteText
+ {
+ Text = Name,
+ Font = OsuFont.Numeric.With(size: 12),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativePositionAxes = Axes.Both,
+ Position = new Vector2(0, -0.25f),
+ Colour = KeyUpTextColor
+ },
+ countSpriteText = new OsuSpriteText
+ {
+ Text = CountPresses.ToString(@"#,0"),
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ RelativePositionAxes = Axes.Both,
+ Position = new Vector2(0, 0.25f),
+ Colour = KeyUpTextColor
+ }
+ }
+ }
+ };
+ // Set this manually because an element with Alpha=0 won't take it size to AutoSizeContainer,
+ // so the size can be changing between buttonSprite and glowSprite.
+ Height = buttonSprite.DrawHeight;
+ Width = buttonSprite.DrawWidth;
+
+ IsLit.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
+ PressesCount.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
+ }
+
+ private void updateGlowSprite(bool show)
+ {
+ if (show)
+ {
+ double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha);
+ glowSprite.FadeIn(remainingFadeTime, Easing.OutQuint);
+ textLayer.FadeColour(KeyDownTextColor, remainingFadeTime, Easing.OutQuint);
+ }
+ else
+ {
+ double remainingFadeTime = 8 * FadeTime * glowSprite.Alpha;
+ glowSprite.FadeOut(remainingFadeTime, Easing.OutQuint);
+ textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint);
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 4405542b3b..a612edbace 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -1,57 +1,37 @@
// Copyright (c) ppy Pty Ltd . 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
-using osu.Framework.Graphics.Textures;
-using osu.Game.Graphics;
-using osu.Game.Graphics.Sprites;
-using osuTK;
-using osuTK.Graphics;
+using osu.Framework.Input.Events;
namespace osu.Game.Screens.Play
{
public abstract partial class KeyCounter : Container
{
- private Sprite buttonSprite;
- private Sprite glowSprite;
- private Container textLayer;
- private SpriteText countSpriteText;
+ public readonly Trigger CounterTrigger;
- public bool IsCounting { get; set; } = true;
- private int countPresses;
+ protected Bindable IsCountingBindable = new BindableBool(true);
+
+ protected Bindable PressesCount = new BindableInt
+ {
+ MinValue = 0
+ };
+
+ public bool IsCounting
+ {
+ get => IsCountingBindable.Value;
+ set => IsCountingBindable.Value = value;
+ }
public int CountPresses
{
- get => countPresses;
- private set
- {
- if (countPresses != value)
- {
- countPresses = value;
- countSpriteText.Text = value.ToString(@"#,0");
- }
- }
+ get => PressesCount.Value;
+ private set => PressesCount.Value = value;
}
- private bool isLit;
-
- public bool IsLit
- {
- get => isLit;
- protected set
- {
- if (isLit != value)
- {
- isLit = value;
- updateGlowSprite(value);
- }
- }
- }
+ protected Bindable IsLit = new BindableBool();
public void Increment()
{
@@ -69,82 +49,51 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- //further: change default values here and in KeyCounterCollection if needed, instead of passing them in every constructor
- public Color4 KeyDownTextColor { get; set; } = Color4.DarkGray;
- public Color4 KeyUpTextColor { get; set; } = Color4.White;
- public double FadeTime { get; set; }
-
- protected KeyCounter(string name)
+ protected override void LoadComplete()
{
- Name = name;
+ Add(CounterTrigger);
+ base.LoadComplete();
}
- [BackgroundDependencyLoader(true)]
- private void load(TextureStore textures)
+ protected override bool Handle(UIEvent e) => CounterTrigger.TriggerEvent(e);
+
+ protected KeyCounter(Trigger trigger)
{
- Children = new Drawable[]
- {
- buttonSprite = new Sprite
- {
- Texture = textures.Get(@"KeyCounter/key-up"),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- },
- glowSprite = new Sprite
- {
- Texture = textures.Get(@"KeyCounter/key-glow"),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Alpha = 0
- },
- textLayer = new Container
- {
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativeSizeAxes = Axes.Both,
- Children = new Drawable[]
- {
- new OsuSpriteText
- {
- Text = Name,
- Font = OsuFont.Numeric.With(size: 12),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.Both,
- Position = new Vector2(0, -0.25f),
- Colour = KeyUpTextColor
- },
- countSpriteText = new OsuSpriteText
- {
- Text = CountPresses.ToString(@"#,0"),
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- RelativePositionAxes = Axes.Both,
- Position = new Vector2(0, 0.25f),
- Colour = KeyUpTextColor
- }
- }
- }
- };
- // Set this manually because an element with Alpha=0 won't take it size to AutoSizeContainer,
- // so the size can be changing between buttonSprite and glowSprite.
- Height = buttonSprite.DrawHeight;
- Width = buttonSprite.DrawWidth;
+ CounterTrigger = trigger;
+ trigger.Target = this;
+ Name = trigger.Name;
}
- private void updateGlowSprite(bool show)
+ public abstract partial class Trigger : Component
{
- if (show)
+ private KeyCounter? target;
+
+ public KeyCounter Target
{
- double remainingFadeTime = FadeTime * (1 - glowSprite.Alpha);
- glowSprite.FadeIn(remainingFadeTime, Easing.OutQuint);
- textLayer.FadeColour(KeyDownTextColor, remainingFadeTime, Easing.OutQuint);
+ set => target = value;
}
- else
+
+ protected Trigger(string name)
{
- double remainingFadeTime = 8 * FadeTime * glowSprite.Alpha;
- glowSprite.FadeOut(remainingFadeTime, Easing.OutQuint);
- textLayer.FadeColour(KeyUpTextColor, remainingFadeTime, Easing.OutQuint);
+ Name = name;
+ }
+
+ protected void Lit(bool increment = true)
+ {
+ if (target == null) return;
+
+ target.IsLit.Value = true;
+ if (increment)
+ target.Increment();
+ }
+
+ protected void Unlit(bool preserve = true)
+ {
+ if (target == null) return;
+
+ target.IsLit.Value = false;
+ if (!preserve)
+ target.Decrement();
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs
index 900d9bcd0e..058dbb1480 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterAction.cs
@@ -7,7 +7,7 @@ using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterAction : KeyCounter
+ public partial class KeyCounterAction : KeyCounter.Trigger
where T : struct
{
public T Action { get; }
@@ -23,9 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- IsLit = true;
- if (forwards)
- Increment();
+ Lit(forwards);
return false;
}
@@ -34,9 +32,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return;
- IsLit = false;
- if (!forwards)
- Decrement();
+ Unlit(forwards);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
index c5c8b7eeae..4306efd360 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
@@ -8,7 +8,7 @@ using osuTK.Input;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterKeyboard : KeyCounter
+ public partial class KeyCounterKeyboard : KeyCounter.Trigger
{
public Key Key { get; }
@@ -21,17 +21,16 @@ namespace osu.Game.Screens.Play
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Key == Key)
- {
- IsLit = true;
- Increment();
- }
+ Lit();
return base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyUpEvent e)
{
- if (e.Key == Key) IsLit = false;
+ if (e.Key == Key)
+ Unlit();
+
base.OnKeyUp(e);
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs
index cf9c7c029f..00fca47ba2 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouse.cs
@@ -9,7 +9,7 @@ using osuTK;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterMouse : KeyCounter
+ public partial class KeyCounterMouse : KeyCounter.Trigger
{
public MouseButton Button { get; }
@@ -39,17 +39,16 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- {
- IsLit = true;
- Increment();
- }
+ Lit();
return base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseUpEvent e)
{
- if (e.Button == Button) IsLit = false;
+ if (e.Button == Button)
+ Unlit();
+
base.OnMouseUp(e);
}
}
From 11d0e185b8188d0986f4520131a14ba95ab2322f Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 01:33:09 +0000
Subject: [PATCH 043/476] refactor: separate impl of KeyCounterDisplay
This allows for different layouts of display. Idk, maybe someone would
want to mix both variants? (don't do this please). This commit is mostly
prep for further changes.
---
.../TestSceneOsuTouchInput.cs | 16 ++--
.../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 18 ++--
.../TestSceneSkinEditorMultipleSkins.cs | 2 +-
.../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +-
.../Screens/Play/DefaultKeyCounterDisplay.cs | 91 +++++++++++++++++++
osu.Game/Screens/Play/HUDOverlay.cs | 2 +-
osu.Game/Screens/Play/KeyCounterDisplay.cs | 76 ++--------------
8 files changed, 121 insertions(+), 88 deletions(-)
create mode 100644 osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 72bcec6045..cd30d8df83 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -34,9 +34,9 @@ namespace osu.Game.Rulesets.Osu.Tests
[Resolved]
private OsuConfigManager config { get; set; } = null!;
- private TestActionKeyCounter leftKeyCounter = null!;
+ private DefaultKeyCounter leftKeyCounter = null!;
- private TestActionKeyCounter rightKeyCounter = null!;
+ private DefaultKeyCounter rightKeyCounter = null!;
private OsuInputManager osuInputManager = null!;
@@ -59,14 +59,14 @@ namespace osu.Game.Rulesets.Osu.Tests
Origin = Anchor.Centre,
Children = new Drawable[]
{
- leftKeyCounter = new TestActionKeyCounter(OsuAction.LeftButton)
+ leftKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.LeftButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Depth = float.MinValue,
X = -100,
},
- rightKeyCounter = new TestActionKeyCounter(OsuAction.RightButton)
+ rightKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.RightButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
@@ -579,7 +579,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action));
private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action));
- public partial class TestActionKeyCounter : KeyCounter, IKeyBindingHandler
+ public partial class TestActionKeyCounter : KeyCounter.Trigger, IKeyBindingHandler
{
public OsuAction Action { get; }
@@ -593,8 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- IsLit = true;
- Increment();
+ Lit();
}
return false;
@@ -602,7 +601,8 @@ namespace osu.Game.Rulesets.Osu.Tests
public void OnReleased(KeyBindingReleaseEvent e)
{
- if (e.Action == Action) IsLit = false;
+ if (e.Action == Action)
+ Unlit();
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index 5e1412d79b..4055ef9d3a 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
scoreProcessor.Combo.Value = 1;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 890ac21b40..60ebce4f52 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -17,28 +17,28 @@ namespace osu.Game.Tests.Visual.Gameplay
{
public TestSceneKeyCounter()
{
- KeyCounterKeyboard testCounter;
+ DefaultKeyCounter testCounter;
- KeyCounterDisplay kc = new KeyCounterDisplay
+ KeyCounterDisplay kc = new DefaultKeyCounterDisplay
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Children = new KeyCounter[]
+ Children = new[]
{
- testCounter = new KeyCounterKeyboard(Key.X),
- new KeyCounterKeyboard(Key.X),
- new KeyCounterMouse(MouseButton.Left),
- new KeyCounterMouse(MouseButton.Right),
+ testCounter = new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
+ new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
+ new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Left)),
+ new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Right)),
},
};
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
- kc.Add(new KeyCounterKeyboard(key));
+ kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboard(key)));
});
- Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key;
+ Key testKey = ((KeyCounterKeyboard)kc.Children.First().CounterTrigger).Key;
void addPressKeyStep()
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
index d5b6ac38cb..56cf56efd9 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
scoreProcessor.Combo.Value = 1;
return new Container
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
index 1f2329af4a..f713bca081 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(new KeyCounterKeyboard(Key.Space));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
action?.Invoke(hudOverlay);
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
new file mode 100644
index 0000000000..d643070e06
--- /dev/null
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -0,0 +1,91 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class DefaultKeyCounterDisplay : KeyCounterDisplay
+ {
+ private const int duration = 100;
+ private const double key_fade_time = 80;
+
+ protected override Container Content => KeyFlow;
+
+ public new IReadOnlyList Children
+ {
+ get => (IReadOnlyList)base.Children;
+ set => base.Children = value;
+ }
+
+ public DefaultKeyCounterDisplay()
+ {
+ InternalChild = KeyFlow = new FillFlowContainer
+ {
+ Direction = FillDirection.Horizontal,
+ AutoSizeAxes = Axes.Both,
+ Alpha = 0,
+ };
+ }
+
+ protected override void Update()
+ {
+ base.Update();
+
+ // Don't use autosize as it will shrink to zero when KeyFlow is hidden.
+ // In turn this can cause the display to be masked off screen and never become visible again.
+ Size = KeyFlow.Size;
+ }
+
+ public override void Add(KeyCounter key)
+ {
+ base.Add(key);
+ if (key is not DefaultKeyCounter defaultKey)
+ throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
+
+ defaultKey.FadeTime = key_fade_time;
+ defaultKey.KeyDownTextColor = KeyDownTextColor;
+ defaultKey.KeyUpTextColor = KeyUpTextColor;
+ }
+
+ protected override void UpdateVisibility() =>
+ // Isolate changing visibility of the key counters from fading this component.
+ KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
+
+ private Color4 keyDownTextColor = Color4.DarkGray;
+
+ public Color4 KeyDownTextColor
+ {
+ get => keyDownTextColor;
+ set
+ {
+ if (value != keyDownTextColor)
+ {
+ keyDownTextColor = value;
+ foreach (var child in Children)
+ child.KeyDownTextColor = value;
+ }
+ }
+ }
+
+ private Color4 keyUpTextColor = Color4.White;
+
+ public Color4 KeyUpTextColor
+ {
+ get => keyUpTextColor;
+ set
+ {
+ if (value != keyUpTextColor)
+ {
+ keyUpTextColor = value;
+ foreach (var child in Children)
+ child.KeyUpTextColor = value;
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index 4d1f0b96b6..a09da14132 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -327,7 +327,7 @@ namespace osu.Game.Screens.Play
ShowHealth = { BindTarget = ShowHealthBar }
};
- protected KeyCounterDisplay CreateKeyCounter() => new KeyCounterDisplay
+ protected KeyCounterDisplay CreateKeyCounter() => new DefaultKeyCounterDisplay
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index bb50d4a539..b06d1adfa0 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -12,18 +12,14 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Configuration;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterDisplay : Container
+ public abstract partial class KeyCounterDisplay : Container
{
- private const int duration = 100;
- private const double key_fade_time = 80;
+ protected readonly Bindable ConfigVisibility = new Bindable();
- private readonly Bindable configVisibility = new Bindable();
-
- protected readonly FillFlowContainer KeyFlow;
+ protected FillFlowContainer KeyFlow;
protected override Container Content => KeyFlow;
@@ -33,48 +29,26 @@ namespace osu.Game.Screens.Play
///
public readonly Bindable AlwaysVisible = new Bindable(true);
- public KeyCounterDisplay()
- {
- InternalChild = KeyFlow = new FillFlowContainer
- {
- Direction = FillDirection.Horizontal,
- AutoSizeAxes = Axes.Both,
- Alpha = 0,
- };
- }
-
- protected override void Update()
- {
- base.Update();
-
- // Don't use autosize as it will shrink to zero when KeyFlow is hidden.
- // In turn this can cause the display to be masked off screen and never become visible again.
- Size = KeyFlow.Size;
- }
-
public override void Add(KeyCounter key)
{
ArgumentNullException.ThrowIfNull(key);
base.Add(key);
key.IsCounting = IsCounting;
- key.FadeTime = key_fade_time;
- key.KeyDownTextColor = KeyDownTextColor;
- key.KeyUpTextColor = KeyUpTextColor;
}
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
- config.BindWith(OsuSetting.KeyOverlay, configVisibility);
+ config.BindWith(OsuSetting.KeyOverlay, ConfigVisibility);
}
protected override void LoadComplete()
{
base.LoadComplete();
- AlwaysVisible.BindValueChanged(_ => updateVisibility());
- configVisibility.BindValueChanged(_ => updateVisibility(), true);
+ AlwaysVisible.BindValueChanged(_ => UpdateVisibility());
+ ConfigVisibility.BindValueChanged(_ => UpdateVisibility(), true);
}
private bool isCounting = true;
@@ -92,41 +66,7 @@ namespace osu.Game.Screens.Play
}
}
- private Color4 keyDownTextColor = Color4.DarkGray;
-
- public Color4 KeyDownTextColor
- {
- get => keyDownTextColor;
- set
- {
- if (value != keyDownTextColor)
- {
- keyDownTextColor = value;
- foreach (var child in Children)
- child.KeyDownTextColor = value;
- }
- }
- }
-
- private Color4 keyUpTextColor = Color4.White;
-
- public Color4 KeyUpTextColor
- {
- get => keyUpTextColor;
- set
- {
- if (value != keyUpTextColor)
- {
- keyUpTextColor = value;
- foreach (var child in Children)
- child.KeyUpTextColor = value;
- }
- }
- }
-
- private void updateVisibility() =>
- // Isolate changing visibility of the key counters from fading this component.
- KeyFlow.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration);
+ protected abstract void UpdateVisibility();
public override bool HandleNonPositionalInput => receptor == null;
public override bool HandlePositionalInput => receptor == null;
@@ -141,6 +81,8 @@ namespace osu.Game.Screens.Play
this.receptor = receptor;
}
+ public virtual KeyCounter CreateKeyCounter(KeyCounter.Trigger trigger) => new DefaultKeyCounter(trigger);
+
public partial class Receptor : Drawable
{
protected readonly KeyCounterDisplay Target;
From aa2e0028ab3c20cb4e0afe412e12670e3b14f96f Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 10:59:10 +0000
Subject: [PATCH 044/476] refactor: hide trigger presence from content
---
osu.Game/Screens/Play/KeyCounter.cs | 32 +++++++++++++++++------------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a612edbace..b111305b22 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -14,6 +14,10 @@ namespace osu.Game.Screens.Play
protected Bindable IsCountingBindable = new BindableBool(true);
+ private readonly Container content;
+
+ protected override Container Content => content;
+
protected Bindable PressesCount = new BindableInt
{
MinValue = 0
@@ -31,6 +35,21 @@ namespace osu.Game.Screens.Play
private set => PressesCount.Value = value;
}
+ protected KeyCounter(Trigger trigger)
+ {
+ InternalChildren = new Drawable[]
+ {
+ content = new Container
+ {
+ RelativeSizeAxes = Axes.Both
+ },
+ CounterTrigger = trigger,
+ };
+
+ CounterTrigger.Target = this;
+ Name = trigger.Name;
+ }
+
protected Bindable IsLit = new BindableBool();
public void Increment()
@@ -49,21 +68,8 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- protected override void LoadComplete()
- {
- Add(CounterTrigger);
- base.LoadComplete();
- }
-
protected override bool Handle(UIEvent e) => CounterTrigger.TriggerEvent(e);
- protected KeyCounter(Trigger trigger)
- {
- CounterTrigger = trigger;
- trigger.Target = this;
- Name = trigger.Name;
- }
-
public abstract partial class Trigger : Component
{
private KeyCounter? target;
From 7aaaf7fca2d598998d7c407a3b259db985484b06 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Tue, 14 Feb 2023 16:55:35 +0900
Subject: [PATCH 045/476] Combine and attempt to simplify the score import /
preparation process further
---
osu.Game/Rulesets/UI/RulesetInputManager.cs | 3 +
osu.Game/Screens/Play/Player.cs | 82 ++++++++++-----------
2 files changed, 43 insertions(+), 42 deletions(-)
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index a5e442b7de..7bf0482673 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -39,6 +39,9 @@ namespace osu.Game.Rulesets.UI
{
set
{
+ if (value == recorder)
+ return;
+
if (value != null && recorder != null)
throw new InvalidOperationException("Cannot attach more than one recorder");
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 0825f36a0a..bc453d2151 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -276,7 +276,7 @@ namespace osu.Game.Screens.Play
},
FailOverlay = new FailOverlay
{
- SaveReplay = prepareAndImportScore,
+ SaveReplay = async () => await prepareAndImportScoreAsync(true).ConfigureAwait(false),
OnRetry = () => Restart(),
OnQuit = () => PerformExit(true),
},
@@ -614,7 +614,7 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate?.Cancel();
// import current score if possible.
- attemptScoreImport();
+ prepareAndImportScoreAsync();
// The actual exit is performed if
// - the pause / fail dialog was not requested
@@ -772,10 +772,7 @@ namespace osu.Game.Screens.Play
if (prepareScoreForDisplayTask == null)
{
// Try importing score since the task hasn't been invoked yet.
- if (!attemptScoreImport())
- // If attempt failed, trying again is unnecessary
- resultsDisplayDelegate?.Cancel();
-
+ prepareAndImportScoreAsync();
return;
}
@@ -785,6 +782,12 @@ namespace osu.Game.Screens.Play
resultsDisplayDelegate?.Cancel();
+ if (prepareScoreForDisplayTask.GetResultSafely() == null)
+ {
+ // If score import did not occur, we do not want to show the results screen.
+ return;
+ }
+
if (!this.IsCurrentScreen())
// This player instance may already be in the process of exiting.
return;
@@ -796,53 +799,48 @@ namespace osu.Game.Screens.Play
}
///
- /// Attempts to run
+ /// Asynchronously run score preparation operations (database import, online submission etc.).
///
- ///
- /// Whether the attempt was successful
- ///
- private bool attemptScoreImport()
+ /// Whether the score should be imported even if non-passing (or the current configuration doesn't allow for it).
+ /// The final score.
+ [ItemCanBeNull]
+ private Task prepareAndImportScoreAsync(bool forceImport = false)
{
// Ensure we are not writing to the replay any more, as we are about to consume and store the score.
DrawableRuleset.SetRecordTarget(null);
+ if (prepareScoreForDisplayTask != null)
+ return prepareScoreForDisplayTask;
+
// We do not want to import the score in cases where we don't show results
bool canShowResults = Configuration.ShowResults && ScoreProcessor.HasCompleted.Value && GameplayState.HasPassed;
- if (!canShowResults)
- return false;
+ if (!canShowResults && !forceImport)
+ return Task.FromResult(null);
- prepareScoreForDisplayTask ??= Task.Run(prepareAndImportScore);
-
- return true;
- }
-
- ///
- /// Asynchronously run score preparation operations (database import, online submission etc.).
- ///
- /// The final score.
- private async Task prepareAndImportScore()
- {
- var scoreCopy = Score.DeepClone();
-
- try
+ return prepareScoreForDisplayTask = Task.Run(async () =>
{
- await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.Error(ex, @"Score preparation failed!");
- }
+ var scoreCopy = Score.DeepClone();
- try
- {
- await ImportScore(scoreCopy).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Logger.Error(ex, @"Score import failed!");
- }
+ try
+ {
+ await PrepareScoreForResultsAsync(scoreCopy).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(ex, @"Score preparation failed!");
+ }
- return scoreCopy.ScoreInfo;
+ try
+ {
+ await ImportScore(scoreCopy).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(ex, @"Score import failed!");
+ }
+
+ return scoreCopy.ScoreInfo;
+ });
}
protected override bool OnScroll(ScrollEvent e)
From d100a4a4915b3c67c48cf790822e93da90dc02be Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 10:12:37 +0100
Subject: [PATCH 046/476] Make `lastJudgedHitObject` nullable, and fix typo in
name.
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 23 ++++++++-------------
1 file changed, 9 insertions(+), 14 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 3e3fce5c27..40c235911c 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -2,8 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -48,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private readonly DrawablePool bubblePool = new DrawablePool(100);
- private DrawableOsuHitObject lastJudgedHitobject = null!;
+ private DrawableOsuHitObject? lastJudgedHitObject;
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
@@ -60,9 +62,11 @@ namespace osu.Game.Rulesets.Osu.Mods
scoreProcessor.NewJudgement += result =>
{
- if (result.HitObject is not OsuHitObject osuHitObject) return;
+ if (result.HitObject is not OsuHitObject osuHitObject || lastJudgedHitObject.IsNull()) return;
- DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitobject;
+ Debug.Assert(result.HitObject == lastJudgedHitObject.HitObject);
+
+ DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitObject;
switch (result.HitObject)
{
@@ -144,18 +148,9 @@ namespace osu.Game.Rulesets.Osu.Mods
applySliderState(slider);
}
- if (osuHitObject == lastJudgedHitobject || !osuHitObject.Judged) return;
+ if (osuHitObject == lastJudgedHitObject || !osuHitObject.Judged) return;
- switch (osuHitObject)
- {
- case DrawableSlider:
- case DrawableSpinnerTick:
- break;
-
- default:
- lastJudgedHitobject = osuHitObject;
- break;
- }
+ lastJudgedHitObject = osuHitObject;
}
// Makes the slider border coloured on all skins (for aesthetics)
From 2d49b5f9d66150598260451250c11736bdad87bc Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 14:03:48 +0100
Subject: [PATCH 047/476] Move bubbles to ruleset overlays container
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 40c235911c..732626b177 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Mods
bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
- drawableRuleset.KeyBindingInputManager.Add(bubbleContainer);
+ drawableRuleset.Overlays.Add(bubbleContainer);
}
protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
From 92c61c73396939363b3c6bd7ffffb083e3c74116 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 16:31:34 +0100
Subject: [PATCH 048/476] move logic for bubble invoking to
`ApplyToDrawableHitobject()`` method
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 85 +++++++++------------
1 file changed, 34 insertions(+), 51 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 732626b177..4a8c11e7ff 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -2,10 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
-using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -25,7 +23,7 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Mods
{
- public partial class OsuModBubbles : ModWithVisibilityAdjustment, IApplicableToDrawableRuleset, IApplicableToScoreProcessor
+ public partial class OsuModBubbles : Mod, IApplicableToDrawableRuleset, IApplicableToDrawableHitObject, IApplicableToScoreProcessor
{
public override string Name => "Bubbles";
@@ -50,8 +48,6 @@ namespace osu.Game.Rulesets.Osu.Mods
private readonly DrawablePool bubblePool = new DrawablePool(100);
- private DrawableOsuHitObject? lastJudgedHitObject;
-
public ScoreRank AdjustRank(ScoreRank rank, double accuracy) => rank;
public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
@@ -60,15 +56,41 @@ namespace osu.Game.Rulesets.Osu.Mods
currentCombo.BindValueChanged(combo =>
maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
- scoreProcessor.NewJudgement += result =>
+ scoreProcessor.JudgementReverted += _ =>
{
- if (result.HitObject is not OsuHitObject osuHitObject || lastJudgedHitObject.IsNull()) return;
+ bubbleContainer.LastOrDefault()?.ClearTransforms();
+ bubbleContainer.LastOrDefault()?.Expire();
+ };
+ }
- Debug.Assert(result.HitObject == lastJudgedHitObject.HitObject);
+ public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
+ {
+ // Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
+ // Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
+ bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
+ bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
- DrawableOsuHitObject drawableOsuHitObject = lastJudgedHitObject;
+ // We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
+ drawableRuleset.Playfield.DisplayJudgements.Value = false;
- switch (result.HitObject)
+ bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
+
+ drawableRuleset.Overlays.Add(bubbleContainer);
+ }
+
+ public void ApplyToDrawableHitObject(DrawableHitObject drawableObject)
+ {
+ if (drawableObject is DrawableSlider slider)
+ {
+ applySliderState(slider);
+ slider.Body.OnSkinChanged += () => applySliderState(slider);
+ }
+
+ drawableObject.OnNewResult += (drawable, _) =>
+ {
+ if (drawable is not DrawableOsuHitObject drawableOsuHitObject) return;
+
+ switch (drawableOsuHitObject.HitObject)
{
case Slider:
case SpinnerTick:
@@ -101,56 +123,17 @@ namespace osu.Game.Rulesets.Osu.Mods
// SliderHeads are derived from HitCircles,
// so we must handle them before to avoid them using the wrong positioning logic
case DrawableSliderHead:
- return osuHitObject.Position;
+ return drawableOsuHitObject.HitObject.Position;
// Using hitobject position will cause issues with HitCircle placement due to stack leniency.
case DrawableHitCircle:
return drawableOsuHitObject.Position;
default:
- return osuHitObject.Position;
+ return drawableOsuHitObject.HitObject.Position;
}
}
};
-
- scoreProcessor.JudgementReverted += _ =>
- {
- bubbleContainer.LastOrDefault()?.FinishTransforms();
- bubbleContainer.LastOrDefault()?.Expire();
- };
- }
-
- public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
- {
- // Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
- // Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
- bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
- bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
-
- // We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
- drawableRuleset.Playfield.DisplayJudgements.Value = false;
-
- bubbleContainer = drawableRuleset.CreatePlayfieldAdjustmentContainer();
-
- drawableRuleset.Overlays.Add(bubbleContainer);
- }
-
- protected override void ApplyIncreasedVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
- protected override void ApplyNormalVisibilityState(DrawableHitObject hitObject, ArmedState state) => applyBubbleState(hitObject);
-
- private void applyBubbleState(DrawableHitObject drawableObject)
- {
- DrawableOsuHitObject osuHitObject = (DrawableOsuHitObject)drawableObject;
-
- if (drawableObject is DrawableSlider slider)
- {
- slider.Body.OnSkinChanged += () => applySliderState(slider);
- applySliderState(slider);
- }
-
- if (osuHitObject == lastJudgedHitObject || !osuHitObject.Judged) return;
-
- lastJudgedHitObject = osuHitObject;
}
// Makes the slider border coloured on all skins (for aesthetics)
From 5db624159b1230e7ca522e9ab6cdec8194e8a0fa Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Tue, 14 Feb 2023 18:06:43 +0100
Subject: [PATCH 049/476] Change bubble rewind removal to be in
`ApplyToDrawableHitObject` method.
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 4a8c11e7ff..f521dfb1f8 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -55,12 +55,6 @@ namespace osu.Game.Rulesets.Osu.Mods
currentCombo.BindTo(scoreProcessor.Combo);
currentCombo.BindValueChanged(combo =>
maxSize = Math.Min(1.75f, (float)(1.25 + 0.005 * combo.NewValue)), true);
-
- scoreProcessor.JudgementReverted += _ =>
- {
- bubbleContainer.LastOrDefault()?.ClearTransforms();
- bubbleContainer.LastOrDefault()?.Expire();
- };
}
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
@@ -134,6 +128,16 @@ namespace osu.Game.Rulesets.Osu.Mods
}
}
};
+
+ drawableObject.OnRevertResult += (drawable, _) =>
+ {
+ if (drawable.HitObject is SpinnerTick or Slider) return;
+
+ BubbleDrawable? lastBubble = bubbleContainer.OfType().LastOrDefault();
+
+ lastBubble?.ClearTransforms();
+ lastBubble?.Expire();
+ };
}
// Makes the slider border coloured on all skins (for aesthetics)
From 82292d61621e49a158c576879ae56f47a9e52a84 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 09:30:12 +0100
Subject: [PATCH 050/476] Make colouring for bubble more intuitive and remove
unnecessary alpha assignment
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index f521dfb1f8..2a4208065d 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -177,8 +177,7 @@ namespace osu.Game.Rulesets.Osu.Mods
protected override void PrepareForUse()
{
- Alpha = 1;
- Colour = Colour4.White;
+ Colour = Info.IsHit ? Colour4.White : Colour4.Black;
Scale = new Vector2(1);
Position = Info.Position;
Size = Info.InitialSize;
@@ -204,12 +203,8 @@ namespace osu.Game.Rulesets.Osu.Mods
content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
-
- return;
}
- Colour = Colour4.Black;
-
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
double getAnimationDuration() => 1700 + Math.Pow(Info.FadeTime, 1.07f);
}
From e9a7d90273c57dbd7dfb30ff32b9ca21dc9b6d39 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 09:33:18 +0100
Subject: [PATCH 051/476] make transform duration for bubble a method instead
of a variable
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 2a4208065d..a88bf6b813 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -187,26 +187,26 @@ namespace osu.Game.Rulesets.Osu.Mods
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
ColourInfo colourDarker = Info.Colour.Darken(0.1f);
+ // The absolute length of the bubble's animation, can be used in fractions for animations of partial length
+ double getAnimationDuration = 1700 + Math.Pow(Info.FadeTime, 1.07f);
+
// Main bubble scaling based on combo
- this.ScaleTo(Info.MaxSize, getAnimationDuration() * 0.8f)
+ this.ScaleTo(Info.MaxSize, getAnimationDuration * 0.8f)
.Then()
// Pop at the end of the bubbles life time
- .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration() * 0.2f, Easing.OutQuint)
- .FadeOutFromOne(getAnimationDuration() * 0.2f, Easing.OutCirc).Expire();
+ .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
+ .FadeOutFromOne(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
if (Info.IsHit)
{
colourBox.FadeColour(colourDarker);
- content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration() * 0.3f, Easing.OutQuint);
+ content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
// Ripple effect utilises the border to reduce drawable count
- content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration() * 0.3f, Easing.OutQuint)
+ content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
}
-
- // The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration() => 1700 + Math.Pow(Info.FadeTime, 1.07f);
}
}
From 1d1c794ccfde23743574d8579da648cf42f4e4d4 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 09:37:47 +0100
Subject: [PATCH 052/476] Invert pointless nested `if` statement
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index a88bf6b813..d75c82dc85 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -197,16 +197,15 @@ namespace osu.Game.Rulesets.Osu.Mods
.ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
.FadeOutFromOne(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
- if (Info.IsHit)
- {
- colourBox.FadeColour(colourDarker);
+ if (!Info.IsHit) return;
- content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
- // Ripple effect utilises the border to reduce drawable count
- content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
- // Avoids transparency overlap issues during the bubble "pop"
- .Then().Schedule(() => content.BorderThickness = 0);
- }
+ colourBox.FadeColour(colourDarker);
+
+ content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
+ // Ripple effect utilises the border to reduce drawable count
+ content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
+ // Avoids transparency overlap issues during the bubble "pop"
+ .Then().Schedule(() => content.BorderThickness = 0);
}
}
From 297963b461cfdfd6083784ab0c4561c43c1d4a93 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 10:00:46 +0100
Subject: [PATCH 053/476] Remove BubbleInfo struct and consume
`DrawableOsuHitObject`s directly
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 102 +++++++++-----------
1 file changed, 46 insertions(+), 56 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index d75c82dc85..981932c580 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -2,8 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Diagnostics;
using System.Linq;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -98,35 +101,14 @@ namespace osu.Game.Rulesets.Osu.Mods
void addBubble()
{
BubbleDrawable bubble = bubblePool.Get();
- bubble.Info = new BubbleInfo
- {
- InitialSize = new Vector2(bubbleRadius),
- MaxSize = maxSize,
- Position = getPosition(),
- FadeTime = bubbleFade,
- Colour = drawableOsuHitObject.AccentColour.Value,
- IsHit = drawableOsuHitObject.IsHit,
- };
+
+ bubble.DrawableOsuHitObject = drawableOsuHitObject;
+ bubble.InitialSize = new Vector2(bubbleRadius);
+ bubble.FadeTime = bubbleFade;
+ bubble.MaxSize = maxSize;
+
bubbleContainer.Add(bubble);
}
-
- Vector2 getPosition()
- {
- switch (drawableOsuHitObject)
- {
- // SliderHeads are derived from HitCircles,
- // so we must handle them before to avoid them using the wrong positioning logic
- case DrawableSliderHead:
- return drawableOsuHitObject.HitObject.Position;
-
- // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
- case DrawableHitCircle:
- return drawableOsuHitObject.Position;
-
- default:
- return drawableOsuHitObject.HitObject.Position;
- }
- }
};
drawableObject.OnRevertResult += (drawable, _) =>
@@ -148,11 +130,15 @@ namespace osu.Game.Rulesets.Osu.Mods
private partial class BubbleDrawable : PoolableDrawable
{
+ public DrawableOsuHitObject? DrawableOsuHitObject { get; set; }
+
+ public Vector2 InitialSize { get; set; }
+ public double FadeTime { get; set; }
+ public float MaxSize { get; set; }
+
private readonly Box colourBox;
private readonly CircularContainer content;
- public BubbleInfo Info { get; set; }
-
public BubbleDrawable()
{
Origin = Anchor.Centre;
@@ -177,27 +163,30 @@ namespace osu.Game.Rulesets.Osu.Mods
protected override void PrepareForUse()
{
- Colour = Info.IsHit ? Colour4.White : Colour4.Black;
+ Debug.Assert(DrawableOsuHitObject.IsNotNull());
+
+ Colour = DrawableOsuHitObject.IsHit ? Colour4.White : Colour4.Black;
+ Alpha = 1;
Scale = new Vector2(1);
- Position = Info.Position;
- Size = Info.InitialSize;
- content.BorderThickness = Info.InitialSize.X / 3.5f;
+ Position = getPosition();
+ Size = InitialSize;
+ content.BorderThickness = InitialSize.X / 3.5f;
content.BorderColour = Colour4.White;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
- ColourInfo colourDarker = Info.Colour.Darken(0.1f);
+ ColourInfo colourDarker = DrawableOsuHitObject.AccentColour.Value.Darken(0.1f);
// The absolute length of the bubble's animation, can be used in fractions for animations of partial length
- double getAnimationDuration = 1700 + Math.Pow(Info.FadeTime, 1.07f);
+ double getAnimationDuration = 1700 + Math.Pow(FadeTime, 1.07f);
// Main bubble scaling based on combo
- this.ScaleTo(Info.MaxSize, getAnimationDuration * 0.8f)
+ this.ScaleTo(MaxSize, getAnimationDuration * 0.8f)
.Then()
// Pop at the end of the bubbles life time
- .ScaleTo(Info.MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
- .FadeOutFromOne(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
+ .ScaleTo(MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
+ .FadeOut(getAnimationDuration * 0.2f, Easing.OutCirc).Expire();
- if (!Info.IsHit) return;
+ if (!DrawableOsuHitObject.IsHit) return;
colourBox.FadeColour(colourDarker);
@@ -206,26 +195,27 @@ namespace osu.Game.Rulesets.Osu.Mods
content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
+
+ Vector2 getPosition()
+ {
+ switch (DrawableOsuHitObject)
+ {
+ // SliderHeads are derived from HitCircles,
+ // so we must handle them before to avoid them using the wrong positioning logic
+ case DrawableSliderHead:
+ return DrawableOsuHitObject.HitObject.Position;
+
+ // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
+ case DrawableHitCircle:
+ return DrawableOsuHitObject.Position;
+
+ default:
+ return DrawableOsuHitObject.HitObject.Position;
+ }
+ }
}
}
- private struct BubbleInfo
- {
- public Vector2 InitialSize { get; set; }
-
- public float MaxSize { get; set; }
-
- public Vector2 Position { get; set; }
-
- public Colour4 Colour { get; set; }
-
- // FadeTime is based on the approach rate of the beatmap.
- public double FadeTime { get; set; }
-
- // Whether the corresponding HitObject was hit
- public bool IsHit { get; set; }
- }
-
#endregion
}
}
From 8fc35b159f87a10a087c79c469d981ff9750bc95 Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Wed, 15 Feb 2023 10:04:50 +0100
Subject: [PATCH 054/476] Remove dysfunctional slider colouring
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 981932c580..4edf726f26 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -18,7 +18,6 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
-using osu.Game.Rulesets.Osu.Skinning.Default;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Scoring;
@@ -77,12 +76,6 @@ namespace osu.Game.Rulesets.Osu.Mods
public void ApplyToDrawableHitObject(DrawableHitObject drawableObject)
{
- if (drawableObject is DrawableSlider slider)
- {
- applySliderState(slider);
- slider.Body.OnSkinChanged += () => applySliderState(slider);
- }
-
drawableObject.OnNewResult += (drawable, _) =>
{
if (drawable is not DrawableOsuHitObject drawableOsuHitObject) return;
@@ -122,10 +115,6 @@ namespace osu.Game.Rulesets.Osu.Mods
};
}
- // Makes the slider border coloured on all skins (for aesthetics)
- private void applySliderState(DrawableSlider slider) =>
- ((PlaySliderBody)slider.Body.Drawable).BorderColour = slider.AccentColour.Value;
-
#region Pooled Bubble drawable
private partial class BubbleDrawable : PoolableDrawable
From 1f586c129c1b27fee148db26846e69eb6febc1d8 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 15 Feb 2023 22:15:44 +0300
Subject: [PATCH 055/476] fix applied
---
osu.Game/Database/LegacyExporter.cs | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 09d6913dd9..c56c17222d 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -3,6 +3,7 @@
#nullable disable
+using System;
using System.Collections.Generic;
using System.IO;
using osu.Framework.Platform;
@@ -18,6 +19,14 @@ namespace osu.Game.Database
public abstract class LegacyExporter
where TModel : class, IHasNamedFiles
{
+ ///
+ /// Max length of filename (including extension)
+ ///
+ ///
+ /// This constant is smaller 256 because adds additional "_" to the end of the path
+ ///
+ private const int max_path = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+
///
/// The file extension for exports (including the leading '.').
///
@@ -33,7 +42,16 @@ namespace osu.Game.Database
UserFileStorage = storage.GetStorageForDirectory(@"files");
}
- protected virtual string GetFilename(TModel item) => item.GetDisplayString();
+ protected virtual string GetFilename(TModel item)
+ {
+ string fileName = item.GetDisplayString();
+
+ int fileNameLength = fileName.Length - FileExtension.Length;
+ if (fileNameLength > max_path)
+ fileName = fileName.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
+
+ return fileName;
+ }
///
/// Exports an item to a legacy (.zip based) package.
From 387a6f1330b3e22360565dd07a4a7048eae3e4d8 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Wed, 15 Feb 2023 22:43:43 +0300
Subject: [PATCH 056/476] Move logic to `Export` method
---
osu.Game/Database/LegacyExporter.cs | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index cd0b50c109..483c3cbd5c 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -43,16 +43,7 @@ namespace osu.Game.Database
UserFileStorage = storage.GetStorageForDirectory(@"files");
}
- protected virtual string GetFilename(TModel item)
- {
- string fileName = item.GetDisplayString();
-
- int fileNameLength = fileName.Length - FileExtension.Length;
- if (fileNameLength > max_path)
- fileName = fileName.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
-
- return fileName;
- }
+ protected virtual string GetFilename(TModel item) => item.GetDisplayString();
///
/// Exports an item to a legacy (.zip based) package.
@@ -68,6 +59,15 @@ namespace osu.Game.Database
.Concat(exportStorage.GetDirectories(string.Empty));
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
+
+ if (filename.Length > max_path)
+ {
+ string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
+
+ filenameWithoutExtension = filenameWithoutExtension.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
+ filename = $"{filenameWithoutExtension}{FileExtension}";
+ }
+
using (var stream = exportStorage.CreateFileSafely(filename))
ExportModelTo(item, stream);
From 157bba78305b3474fecc5a529b95c954b994e9e9 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 21:59:17 +0000
Subject: [PATCH 057/476] refactor: rename `Trigger` class to `InputTrigger`
---
.../TestSceneOsuTouchInput.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 2 +-
osu.Game/Rulesets/UI/RulesetInputManager.cs | 6 +++---
osu.Game/Screens/Play/DefaultKeyCounter.cs | 2 +-
osu.Game/Screens/Play/KeyCounter.cs | 14 +++++++-------
osu.Game/Screens/Play/KeyCounterAction.cs | 2 +-
osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 +-
osu.Game/Screens/Play/KeyCounterKeyboard.cs | 2 +-
osu.Game/Screens/Play/KeyCounterMouse.cs | 2 +-
9 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index cd30d8df83..1a273153bd 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -579,7 +579,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action));
private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action));
- public partial class TestActionKeyCounter : KeyCounter.Trigger, IKeyBindingHandler
+ public partial class TestActionKeyCounter : KeyCounter.InputTrigger, IKeyBindingHandler
{
public OsuAction Action { get; }
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 60ebce4f52..f652a62489 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay
kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboard(key)));
});
- Key testKey = ((KeyCounterKeyboard)kc.Children.First().CounterTrigger).Key;
+ Key testKey = ((KeyCounterKeyboard)kc.Children.First().Trigger).Key;
void addPressKeyStep()
{
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 0fa1f0b332..22dc6567eb 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -176,14 +176,14 @@ namespace osu.Game.Rulesets.UI
{
}
- public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.CounterTrigger is KeyCounterAction)
- .Select(c => (KeyCounterAction)c.CounterTrigger)
+ public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.Trigger is KeyCounterAction)
+ .Select(c => (KeyCounterAction)c.Trigger)
.Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
public void OnReleased(KeyBindingReleaseEvent e)
{
foreach (var c
- in Target.Children.Where(c => c.CounterTrigger is KeyCounterAction).Select(c => (KeyCounterAction)c.CounterTrigger))
+ in Target.Children.Where(c => c.Trigger is KeyCounterAction).Select(c => (KeyCounterAction)c.Trigger))
c.OnReleased(e.Action, Clock.Rate >= 0);
}
}
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
index dcb425ae1d..93dc4abcb5 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounter.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Screens.Play
public Color4 KeyUpTextColor { get; set; } = Color4.White;
public double FadeTime { get; set; }
- public DefaultKeyCounter(Trigger trigger)
+ public DefaultKeyCounter(InputTrigger trigger)
: base(trigger)
{
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index b111305b22..a1950a49f4 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -10,7 +10,7 @@ namespace osu.Game.Screens.Play
{
public abstract partial class KeyCounter : Container
{
- public readonly Trigger CounterTrigger;
+ public readonly InputTrigger Trigger;
protected Bindable IsCountingBindable = new BindableBool(true);
@@ -35,7 +35,7 @@ namespace osu.Game.Screens.Play
private set => PressesCount.Value = value;
}
- protected KeyCounter(Trigger trigger)
+ protected KeyCounter(InputTrigger trigger)
{
InternalChildren = new Drawable[]
{
@@ -43,10 +43,10 @@ namespace osu.Game.Screens.Play
{
RelativeSizeAxes = Axes.Both
},
- CounterTrigger = trigger,
+ Trigger = trigger,
};
- CounterTrigger.Target = this;
+ Trigger.Target = this;
Name = trigger.Name;
}
@@ -68,9 +68,9 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- protected override bool Handle(UIEvent e) => CounterTrigger.TriggerEvent(e);
+ protected override bool Handle(UIEvent e) => Trigger.TriggerEvent(e);
- public abstract partial class Trigger : Component
+ public abstract partial class InputTrigger : Component
{
private KeyCounter? target;
@@ -79,7 +79,7 @@ namespace osu.Game.Screens.Play
set => target = value;
}
- protected Trigger(string name)
+ protected InputTrigger(string name)
{
Name = name;
}
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs
index 058dbb1480..4926970960 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterAction.cs
@@ -7,7 +7,7 @@ using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterAction : KeyCounter.Trigger
+ public partial class KeyCounterAction : KeyCounter.InputTrigger
where T : struct
{
public T Action { get; }
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index b06d1adfa0..fc6fa12f10 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -81,7 +81,7 @@ namespace osu.Game.Screens.Play
this.receptor = receptor;
}
- public virtual KeyCounter CreateKeyCounter(KeyCounter.Trigger trigger) => new DefaultKeyCounter(trigger);
+ public virtual KeyCounter CreateKeyCounter(KeyCounter.InputTrigger trigger) => new DefaultKeyCounter(trigger);
public partial class Receptor : Drawable
{
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
index 4306efd360..6ae1a2c5bc 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
@@ -8,7 +8,7 @@ using osuTK.Input;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterKeyboard : KeyCounter.Trigger
+ public partial class KeyCounterKeyboard : KeyCounter.InputTrigger
{
public Key Key { get; }
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs
index 00fca47ba2..40674cdbcd 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouse.cs
@@ -9,7 +9,7 @@ using osuTK;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterMouse : KeyCounter.Trigger
+ public partial class KeyCounterMouse : KeyCounter.InputTrigger
{
public MouseButton Button { get; }
From df0633858cb9aa0734a95e5f67fc284313571485 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 23:20:23 +0000
Subject: [PATCH 058/476] fix(KeyCounter): don't override Handle
This caused the Keyboard inputs to register twice, which is not what we
want.
---
osu.Game/Screens/Play/KeyCounter.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a1950a49f4..cd306dfb9b 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -4,7 +4,6 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Input.Events;
namespace osu.Game.Screens.Play
{
@@ -68,8 +67,6 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
- protected override bool Handle(UIEvent e) => Trigger.TriggerEvent(e);
-
public abstract partial class InputTrigger : Component
{
private KeyCounter? target;
From a644fae3649f29eacf612b2bd920fc4ad0a8ec48 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 23:22:50 +0000
Subject: [PATCH 059/476] style(KeyCounter): rename `(Un)lit` methods to
`(Un)light`
---
osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs | 4 ++--
osu.Game/Screens/Play/KeyCounter.cs | 4 ++--
osu.Game/Screens/Play/KeyCounterAction.cs | 4 ++--
osu.Game/Screens/Play/KeyCounterKeyboard.cs | 6 ++++--
osu.Game/Screens/Play/KeyCounterMouse.cs | 4 ++--
5 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 1a273153bd..6068cf50b6 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -593,7 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- Lit();
+ Light();
}
return false;
@@ -602,7 +602,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public void OnReleased(KeyBindingReleaseEvent e)
{
if (e.Action == Action)
- Unlit();
+ Unlight();
}
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index cd306dfb9b..4a7203870c 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -81,7 +81,7 @@ namespace osu.Game.Screens.Play
Name = name;
}
- protected void Lit(bool increment = true)
+ protected void Light(bool increment = true)
{
if (target == null) return;
@@ -90,7 +90,7 @@ namespace osu.Game.Screens.Play
target.Increment();
}
- protected void Unlit(bool preserve = true)
+ protected void Unlight(bool preserve = true)
{
if (target == null) return;
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterAction.cs
index 4926970960..65a0bc2ca7 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterAction.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- Lit(forwards);
+ Light(forwards);
return false;
}
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return;
- Unlit(forwards);
+ Unlight(forwards);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
index 6ae1a2c5bc..ef1f207556 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboard.cs
@@ -21,7 +21,9 @@ namespace osu.Game.Screens.Play
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Key == Key)
- Lit();
+ {
+ Light();
+ }
return base.OnKeyDown(e);
}
@@ -29,7 +31,7 @@ namespace osu.Game.Screens.Play
protected override void OnKeyUp(KeyUpEvent e)
{
if (e.Key == Key)
- Unlit();
+ Unlight();
base.OnKeyUp(e);
}
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouse.cs
index 40674cdbcd..cf0e0a394f 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouse.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- Lit();
+ Light();
return base.OnMouseDown(e);
}
@@ -47,7 +47,7 @@ namespace osu.Game.Screens.Play
protected override void OnMouseUp(MouseUpEvent e)
{
if (e.Button == Button)
- Unlit();
+ Unlight();
base.OnMouseUp(e);
}
From 076eb81b212caaa61546ad3d3d0605b5e072eb46 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Mon, 13 Feb 2023 23:49:57 +0000
Subject: [PATCH 060/476] refactor: rename trigger classes
Makes it better to understand their purpose
---
.../TestSceneOsuTouchInput.cs | 8 ++++----
.../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 12 ++++++------
.../Gameplay/TestSceneSkinEditorMultipleSkins.cs | 2 +-
.../Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +-
osu.Game/Rulesets/UI/RulesetInputManager.cs | 8 ++++----
...eyCounterAction.cs => KeyCounterActionTrigger.cs} | 4 ++--
...unterKeyboard.cs => KeyCounterKeyboardTrigger.cs} | 4 ++--
...{KeyCounterMouse.cs => KeyCounterMouseTrigger.cs} | 4 ++--
9 files changed, 23 insertions(+), 23 deletions(-)
rename osu.Game/Screens/Play/{KeyCounterAction.cs => KeyCounterActionTrigger.cs} (86%)
rename osu.Game/Screens/Play/{KeyCounterKeyboard.cs => KeyCounterKeyboardTrigger.cs} (85%)
rename osu.Game/Screens/Play/{KeyCounterMouse.cs => KeyCounterMouseTrigger.cs} (90%)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 6068cf50b6..950e034d8f 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -59,14 +59,14 @@ namespace osu.Game.Rulesets.Osu.Tests
Origin = Anchor.Centre,
Children = new Drawable[]
{
- leftKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.LeftButton))
+ leftKeyCounter = new DefaultKeyCounter(new TestActionKeyCounterTrigger(OsuAction.LeftButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Depth = float.MinValue,
X = -100,
},
- rightKeyCounter = new DefaultKeyCounter(new TestActionKeyCounter(OsuAction.RightButton))
+ rightKeyCounter = new DefaultKeyCounter(new TestActionKeyCounterTrigger(OsuAction.RightButton))
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
@@ -579,11 +579,11 @@ namespace osu.Game.Rulesets.Osu.Tests
private void checkNotPressed(OsuAction action) => AddAssert($"Not pressing {action}", () => !osuInputManager.PressedActions.Contains(action));
private void checkPressed(OsuAction action) => AddAssert($"Is pressing {action}", () => osuInputManager.PressedActions.Contains(action));
- public partial class TestActionKeyCounter : KeyCounter.InputTrigger, IKeyBindingHandler
+ public partial class TestActionKeyCounterTrigger : KeyCounter.InputTrigger, IKeyBindingHandler
{
public OsuAction Action { get; }
- public TestActionKeyCounter(OsuAction action)
+ public TestActionKeyCounterTrigger(OsuAction action)
: base(action.ToString())
{
Action = action;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index 4055ef9d3a..af79650d29 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
scoreProcessor.Combo.Value = 1;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index f652a62489..975a5c9465 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -25,20 +25,20 @@ namespace osu.Game.Tests.Visual.Gameplay
Anchor = Anchor.Centre,
Children = new[]
{
- testCounter = new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
- new DefaultKeyCounter(new KeyCounterKeyboard(Key.X)),
- new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Left)),
- new DefaultKeyCounter(new KeyCounterMouse(MouseButton.Right)),
+ testCounter = new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
},
};
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
- kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboard(key)));
+ kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
});
- Key testKey = ((KeyCounterKeyboard)kc.Children.First().Trigger).Key;
+ Key testKey = ((KeyCounterKeyboardTrigger)kc.Children.First().Trigger).Key;
void addPressKeyStep()
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
index 56cf56efd9..432ff2fc7e 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
scoreProcessor.Combo.Value = 1;
return new Container
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
index f713bca081..24de29fa03 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboard(Key.Space)));
+ hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
action?.Invoke(hudOverlay);
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 22dc6567eb..6a38fa4824 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.UI
.Select(b => b.GetAction())
.Distinct()
.OrderBy(action => action)
- .Select(action => keyCounter.CreateKeyCounter(new KeyCounterAction(action))));
+ .Select(action => keyCounter.CreateKeyCounter(new KeyCounterActionTrigger(action))));
}
private partial class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler
@@ -176,14 +176,14 @@ namespace osu.Game.Rulesets.UI
{
}
- public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.Trigger is KeyCounterAction)
- .Select(c => (KeyCounterAction)c.Trigger)
+ public bool OnPressed(KeyBindingPressEvent e) => Target.Children.Where(c => c.Trigger is KeyCounterActionTrigger)
+ .Select(c => (KeyCounterActionTrigger)c.Trigger)
.Any(c => c.OnPressed(e.Action, Clock.Rate >= 0));
public void OnReleased(KeyBindingReleaseEvent e)
{
foreach (var c
- in Target.Children.Where(c => c.Trigger is KeyCounterAction).Select(c => (KeyCounterAction)c.Trigger))
+ in Target.Children.Where(c => c.Trigger is KeyCounterActionTrigger).Select(c => (KeyCounterActionTrigger)c.Trigger))
c.OnReleased(e.Action, Clock.Rate >= 0);
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterAction.cs b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
similarity index 86%
rename from osu.Game/Screens/Play/KeyCounterAction.cs
rename to osu.Game/Screens/Play/KeyCounterActionTrigger.cs
index 65a0bc2ca7..51b82ac5e5 100644
--- a/osu.Game/Screens/Play/KeyCounterAction.cs
+++ b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
@@ -7,12 +7,12 @@ using System.Collections.Generic;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterAction : KeyCounter.InputTrigger
+ public partial class KeyCounterActionTrigger : KeyCounter.InputTrigger
where T : struct
{
public T Action { get; }
- public KeyCounterAction(T action)
+ public KeyCounterActionTrigger(T action)
: base($"B{(int)(object)action + 1}")
{
Action = action;
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboard.cs b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
similarity index 85%
rename from osu.Game/Screens/Play/KeyCounterKeyboard.cs
rename to osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
index ef1f207556..fee716abf4 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboard.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
@@ -8,11 +8,11 @@ using osuTK.Input;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterKeyboard : KeyCounter.InputTrigger
+ public partial class KeyCounterKeyboardTrigger : KeyCounter.InputTrigger
{
public Key Key { get; }
- public KeyCounterKeyboard(Key key)
+ public KeyCounterKeyboardTrigger(Key key)
: base(key.ToString())
{
Key = key;
diff --git a/osu.Game/Screens/Play/KeyCounterMouse.cs b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
similarity index 90%
rename from osu.Game/Screens/Play/KeyCounterMouse.cs
rename to osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
index cf0e0a394f..a693db9b19 100644
--- a/osu.Game/Screens/Play/KeyCounterMouse.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
@@ -9,11 +9,11 @@ using osuTK;
namespace osu.Game.Screens.Play
{
- public partial class KeyCounterMouse : KeyCounter.InputTrigger
+ public partial class KeyCounterMouseTrigger : KeyCounter.InputTrigger
{
public MouseButton Button { get; }
- public KeyCounterMouse(MouseButton button)
+ public KeyCounterMouseTrigger(MouseButton button)
: base(getStringRepresentation(button))
{
Button = button;
From b0a2e69f951910907559d16fc2392a4d9867cd99 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 15 Feb 2023 22:06:10 +0000
Subject: [PATCH 061/476] style: nullable pass on `KeyCounterDisplay`
---
osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs | 11 +++++------
osu.Game/Screens/Play/KeyCounterDisplay.cs | 6 ++----
2 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index d643070e06..332474a517 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -24,12 +24,11 @@ namespace osu.Game.Screens.Play
public DefaultKeyCounterDisplay()
{
- InternalChild = KeyFlow = new FillFlowContainer
- {
- Direction = FillDirection.Horizontal,
- AutoSizeAxes = Axes.Both,
- Alpha = 0,
- };
+ KeyFlow.Direction = FillDirection.Horizontal;
+ KeyFlow.AutoSizeAxes = Axes.Both;
+ KeyFlow.Alpha = 0;
+
+ InternalChild = KeyFlow;
}
protected override void Update()
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index fc6fa12f10..f5af67caea 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using osu.Framework.Allocation;
@@ -19,7 +17,7 @@ namespace osu.Game.Screens.Play
{
protected readonly Bindable ConfigVisibility = new Bindable();
- protected FillFlowContainer KeyFlow;
+ protected FillFlowContainer KeyFlow = new FillFlowContainer();
protected override Container Content => KeyFlow;
@@ -71,7 +69,7 @@ namespace osu.Game.Screens.Play
public override bool HandleNonPositionalInput => receptor == null;
public override bool HandlePositionalInput => receptor == null;
- private Receptor receptor;
+ private Receptor? receptor;
public void SetReceptor(Receptor receptor)
{
From e9dcc257b48ae26302c598df7d433e09007a40ba Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 15 Feb 2023 22:06:35 +0000
Subject: [PATCH 062/476] reafactor: simplify type checking
---
osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs | 6 +++---
osu.Game/Screens/Play/KeyCounterDisplay.cs | 5 ++++-
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index 332474a517..b69ecfd7ae 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -43,14 +42,15 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
base.Add(key);
- if (key is not DefaultKeyCounter defaultKey)
- throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
+ DefaultKeyCounter defaultKey = (DefaultKeyCounter)key;
defaultKey.FadeTime = key_fade_time;
defaultKey.KeyDownTextColor = KeyDownTextColor;
defaultKey.KeyUpTextColor = KeyUpTextColor;
}
+ protected override bool CheckType(KeyCounter key) => key is DefaultKeyCounter;
+
protected override void UpdateVisibility() =>
// Isolate changing visibility of the key counters from fading this component.
KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index f5af67caea..ed47af11a3 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -29,12 +29,15 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
- ArgumentNullException.ThrowIfNull(key);
+ if (!CheckType(key))
+ throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
base.Add(key);
key.IsCounting = IsCounting;
}
+ protected virtual bool CheckType(KeyCounter key) => true;
+
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
From 74e7cc205601bc4edb9d88e12afb8c63f8e967d2 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 15 Feb 2023 22:18:02 +0000
Subject: [PATCH 063/476] feat: implement new design of key counter
---
.../Visual/Gameplay/TestSceneKeyCounter.cs | 39 +++++++---
osu.Game/Screens/Play/ArgonKeyCounter.cs | 76 +++++++++++++++++++
.../Screens/Play/ArgonKeyCounterDisplay.cs | 42 ++++++++++
3 files changed, 147 insertions(+), 10 deletions(-)
create mode 100644 osu.Game/Screens/Play/ArgonKeyCounter.cs
create mode 100644 osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 975a5c9465..41add82245 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -8,6 +8,7 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Screens.Play;
+using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
@@ -18,24 +19,44 @@ namespace osu.Game.Tests.Visual.Gameplay
public TestSceneKeyCounter()
{
DefaultKeyCounter testCounter;
+ KeyCounterDisplay kc;
+ KeyCounterDisplay argonKc;
- KeyCounterDisplay kc = new DefaultKeyCounterDisplay
+ Children = new Drawable[]
{
- Origin = Anchor.Centre,
- Anchor = Anchor.Centre,
- Children = new[]
+ kc = new DefaultKeyCounterDisplay
{
- testCounter = new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
- new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
- new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
- new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Position = new Vector2(0, -50),
+ Children = new[]
+ {
+ testCounter = new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
+ new DefaultKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
+ },
},
+ argonKc = new ArgonKeyCounterDisplay
+ {
+ Origin = Anchor.Centre,
+ Anchor = Anchor.Centre,
+ Position = new Vector2(0, 50),
+ Children = new[]
+ {
+ new ArgonKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new ArgonKeyCounter(new KeyCounterKeyboardTrigger(Key.X)),
+ new ArgonKeyCounter(new KeyCounterMouseTrigger(MouseButton.Left)),
+ new ArgonKeyCounter(new KeyCounterMouseTrigger(MouseButton.Right)),
+ },
+ }
};
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
+ argonKc.Add(argonKc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
});
Key testKey = ((KeyCounterKeyboardTrigger)kc.Children.First().Trigger).Key;
@@ -52,8 +73,6 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Disable counting", () => testCounter.IsCounting = false);
addPressKeyStep();
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses == 2);
-
- Add(kc);
}
}
}
diff --git a/osu.Game/Screens/Play/ArgonKeyCounter.cs b/osu.Game/Screens/Play/ArgonKeyCounter.cs
new file mode 100644
index 0000000000..a275a7e017
--- /dev/null
+++ b/osu.Game/Screens/Play/ArgonKeyCounter.cs
@@ -0,0 +1,76 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osuTK;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class ArgonKeyCounter : KeyCounter
+ {
+ private Circle inputIndicator = null!;
+ private OsuSpriteText countText = null!;
+
+ // These values were taken from Figma
+ private const float line_height = 3;
+ private const float name_font_size = 10;
+ private const float count_font_size = 14;
+
+ // Make things look bigger without using Scale
+ private const float scale_factor = 1.5f;
+
+ public ArgonKeyCounter(InputTrigger trigger)
+ : base(trigger)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ Children = new Drawable[]
+ {
+ inputIndicator = new Circle
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ RelativeSizeAxes = Axes.X,
+ Height = line_height * scale_factor,
+ Alpha = 0.5f
+ },
+ new OsuSpriteText
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ Position = new Vector2(0, -13) * scale_factor,
+ Font = OsuFont.Torus.With(size: name_font_size * scale_factor, weight: FontWeight.Bold),
+ Colour = colours.Blue0,
+ Text = Name
+ },
+ countText = new OsuSpriteText
+ {
+ Anchor = Anchor.BottomLeft,
+ Origin = Anchor.BottomLeft,
+ Font = OsuFont.Torus.With(size: count_font_size * scale_factor, weight: FontWeight.Bold),
+ Text = "0"
+ },
+ };
+
+ // Values from Figma didn't match visually
+ // So these were just eyeballed
+ Height = 30 * scale_factor;
+ Width = 35 * scale_factor;
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ IsLit.BindValueChanged(e => inputIndicator.Alpha = e.NewValue ? 1 : 0.5f, true);
+ PressesCount.BindValueChanged(e => countText.Text = e.NewValue.ToString(@"#,0"), true);
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs b/osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
new file mode 100644
index 0000000000..da34a64a4c
--- /dev/null
+++ b/osu.Game/Screens/Play/ArgonKeyCounterDisplay.cs
@@ -0,0 +1,42 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osuTK;
+
+namespace osu.Game.Screens.Play
+{
+ public partial class ArgonKeyCounterDisplay : KeyCounterDisplay
+ {
+ private const int duration = 100;
+
+ public new IReadOnlyList Children
+ {
+ get => (IReadOnlyList)base.Children;
+ set => base.Children = value;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ KeyFlow.Direction = FillDirection.Horizontal;
+ KeyFlow.AutoSizeAxes = Axes.Both;
+ KeyFlow.Spacing = new Vector2(2);
+
+ InternalChildren = new[]
+ {
+ KeyFlow
+ };
+ }
+
+ protected override bool CheckType(KeyCounter key) => key is ArgonKeyCounter;
+
+ protected override void UpdateVisibility()
+ => KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
+
+ public override KeyCounter CreateKeyCounter(KeyCounter.InputTrigger trigger) => new ArgonKeyCounter(trigger);
+ }
+}
From d5bc8e2941fc0a6d948fda24546cc976b12165fa Mon Sep 17 00:00:00 2001
From: mk56-spn
Date: Thu, 16 Feb 2023 11:12:30 +0100
Subject: [PATCH 064/476] Code cleanup pass:
Make bubble transform logic more sane.
Extract bubble `getPosition()` method.
Address poorly named variables.
---
osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs | 47 +++++++++++----------
1 file changed, 25 insertions(+), 22 deletions(-)
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
index 4edf726f26..0fc27c8f1d 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModBubbles.cs
@@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Mods
private readonly Bindable currentCombo = new BindableInt();
private float maxSize;
- private float bubbleRadius;
+ private float bubbleSize;
private double bubbleFade;
private readonly DrawablePool bubblePool = new DrawablePool(100);
@@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Mods
{
// Multiplying by 2 results in an initial size that is too large, hence 1.90 has been chosen
// Also avoids the HitObject bleeding around the edges of the bubble drawable at minimum size
- bubbleRadius = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
+ bubbleSize = (float)(drawableRuleset.Beatmap.HitObjects.OfType().First().Radius * 1.90f);
bubbleFade = drawableRuleset.Beatmap.HitObjects.OfType().First().TimePreempt * 2;
// We want to hide the judgements since they are obscured by the BubbleDrawable (due to layering)
@@ -96,7 +96,7 @@ namespace osu.Game.Rulesets.Osu.Mods
BubbleDrawable bubble = bubblePool.Get();
bubble.DrawableOsuHitObject = drawableOsuHitObject;
- bubble.InitialSize = new Vector2(bubbleRadius);
+ bubble.InitialSize = new Vector2(bubbleSize);
bubble.FadeTime = bubbleFade;
bubble.MaxSize = maxSize;
@@ -122,9 +122,11 @@ namespace osu.Game.Rulesets.Osu.Mods
public DrawableOsuHitObject? DrawableOsuHitObject { get; set; }
public Vector2 InitialSize { get; set; }
- public double FadeTime { get; set; }
+
public float MaxSize { get; set; }
+ public double FadeTime { get; set; }
+
private readonly Box colourBox;
private readonly CircularContainer content;
@@ -155,12 +157,9 @@ namespace osu.Game.Rulesets.Osu.Mods
Debug.Assert(DrawableOsuHitObject.IsNotNull());
Colour = DrawableOsuHitObject.IsHit ? Colour4.White : Colour4.Black;
- Alpha = 1;
Scale = new Vector2(1);
- Position = getPosition();
+ Position = getPosition(DrawableOsuHitObject);
Size = InitialSize;
- content.BorderThickness = InitialSize.X / 3.5f;
- content.BorderColour = Colour4.White;
//We want to fade to a darker colour to avoid colours such as white hiding the "ripple" effect.
ColourInfo colourDarker = DrawableOsuHitObject.AccentColour.Value.Darken(0.1f);
@@ -169,7 +168,8 @@ namespace osu.Game.Rulesets.Osu.Mods
double getAnimationDuration = 1700 + Math.Pow(FadeTime, 1.07f);
// Main bubble scaling based on combo
- this.ScaleTo(MaxSize, getAnimationDuration * 0.8f)
+ this.FadeTo(1)
+ .ScaleTo(MaxSize, getAnimationDuration * 0.8f)
.Then()
// Pop at the end of the bubbles life time
.ScaleTo(MaxSize * 1.5f, getAnimationDuration * 0.2f, Easing.OutQuint)
@@ -177,6 +177,9 @@ namespace osu.Game.Rulesets.Osu.Mods
if (!DrawableOsuHitObject.IsHit) return;
+ content.BorderThickness = InitialSize.X / 3.5f;
+ content.BorderColour = Colour4.White;
+
colourBox.FadeColour(colourDarker);
content.TransformTo(nameof(BorderColour), colourDarker, getAnimationDuration * 0.3f, Easing.OutQuint);
@@ -184,23 +187,23 @@ namespace osu.Game.Rulesets.Osu.Mods
content.TransformTo(nameof(BorderThickness), 2f, getAnimationDuration * 0.3f, Easing.OutQuint)
// Avoids transparency overlap issues during the bubble "pop"
.Then().Schedule(() => content.BorderThickness = 0);
+ }
- Vector2 getPosition()
+ private Vector2 getPosition(DrawableOsuHitObject drawableOsuHitObject)
+ {
+ switch (drawableOsuHitObject)
{
- switch (DrawableOsuHitObject)
- {
- // SliderHeads are derived from HitCircles,
- // so we must handle them before to avoid them using the wrong positioning logic
- case DrawableSliderHead:
- return DrawableOsuHitObject.HitObject.Position;
+ // SliderHeads are derived from HitCircles,
+ // so we must handle them before to avoid them using the wrong positioning logic
+ case DrawableSliderHead:
+ return drawableOsuHitObject.HitObject.Position;
- // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
- case DrawableHitCircle:
- return DrawableOsuHitObject.Position;
+ // Using hitobject position will cause issues with HitCircle placement due to stack leniency.
+ case DrawableHitCircle:
+ return drawableOsuHitObject.Position;
- default:
- return DrawableOsuHitObject.HitObject.Position;
- }
+ default:
+ return drawableOsuHitObject.HitObject.Position;
}
}
}
From f1da213beaaaba85b82c785def1c43f6cb1f62ec Mon Sep 17 00:00:00 2001
From: Cootz
Date: Thu, 16 Feb 2023 16:26:57 +0300
Subject: [PATCH 065/476] Add tests
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 85 +++++++++++++++++++
osu.Game/Database/LegacyExporter.cs | 6 +-
2 files changed, 88 insertions(+), 3 deletions(-)
create mode 100644 osu.Game.Tests/Database/LegacyExporterTest.cs
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
new file mode 100644
index 0000000000..5f07e6c917
--- /dev/null
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -0,0 +1,85 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using NUnit.Framework;
+using osu.Framework.Platform;
+using osu.Framework.Testing;
+using osu.Game.Database;
+
+namespace osu.Game.Tests.Database
+{
+ public class LegacyExporterTest
+ {
+ private TestLegacyExporter? legacyExporter;
+ private TemporaryNativeStorage? storage;
+
+ [SetUp]
+ public void SetupLegacyExporter()
+ {
+ storage = new TemporaryNativeStorage("export-storage");
+ legacyExporter = new TestLegacyExporter(storage);
+ }
+
+ [Test]
+ public void ExportFileWithNormalName()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ string filename = "normal file name";
+ var item = new TestPathInfo(filename);
+
+ Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.DoesNotThrow(() => legacyExporter?.Export(item));
+ Assert.That(exportStorage?.Exists($"{filename}{legacyExporter?.GetExtension()}"), Is.True);
+ }
+
+ [Test]
+ public void ExportFileWithSuperLongName()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+
+ int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ string expectedName = fullname.Remove(capacity);
+
+ var item = new TestPathInfo(fullname);
+
+ Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.DoesNotThrow(() => legacyExporter?.Export(item));
+ Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
+ }
+
+ [TearDown]
+ public void CleanupAfterTest()
+ {
+ storage?.Dispose();
+ }
+
+ private class TestPathInfo : IHasNamedFiles
+ {
+ public string FileName { get; set; } = string.Empty;
+
+ public TestPathInfo(string fileName) => FileName = fileName;
+
+ public IEnumerable Files { get; set; } = new List();
+
+ public override string ToString() => FileName;
+ }
+
+ private class TestLegacyExporter : LegacyExporter
+ {
+ public TestLegacyExporter(Storage storage) : base(storage) { }
+
+ public static int GetMaxPath() => MAX_PATH;
+
+ public string GetExtension() => FileExtension;
+
+ protected override string FileExtension => ".ots";
+ }
+ }
+}
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 483c3cbd5c..9041f58368 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -26,7 +26,7 @@ namespace osu.Game.Database
///
/// This constant is smaller 256 because adds additional "_" to the end of the path
///
- private const int max_path = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ protected const int MAX_PATH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
///
/// The file extension for exports (including the leading '.').
@@ -60,11 +60,11 @@ namespace osu.Game.Database
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- if (filename.Length > max_path)
+ if (filename.Length > MAX_PATH)
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
- filenameWithoutExtension = filenameWithoutExtension.Remove(max_path - FileExtension.Length); //Truncating the name to fit the path limit
+ filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_PATH - FileExtension.Length); //Truncating the name to fit the path limit
filename = $"{filenameWithoutExtension}{FileExtension}";
}
From 6819a45a1bdba3fdd2b28a6d7983b73116ddbded Mon Sep 17 00:00:00 2001
From: Cootz
Date: Thu, 16 Feb 2023 16:42:07 +0300
Subject: [PATCH 066/476] Improve code slightly
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 5f07e6c917..c464eb5c28 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -2,9 +2,6 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Text;
using NUnit.Framework;
using osu.Framework.Platform;
using osu.Framework.Testing;
@@ -29,7 +26,7 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
- string filename = "normal file name";
+ const string filename = "normal file name";
var item = new TestPathInfo(filename);
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
@@ -42,7 +39,7 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
- string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
string expectedName = fullname.Remove(capacity);
@@ -62,7 +59,7 @@ namespace osu.Game.Tests.Database
private class TestPathInfo : IHasNamedFiles
{
- public string FileName { get; set; } = string.Empty;
+ public string FileName { get; set; }
public TestPathInfo(string fileName) => FileName = fileName;
@@ -73,7 +70,10 @@ namespace osu.Game.Tests.Database
private class TestLegacyExporter : LegacyExporter
{
- public TestLegacyExporter(Storage storage) : base(storage) { }
+ public TestLegacyExporter(Storage storage)
+ : base(storage)
+ {
+ }
public static int GetMaxPath() => MAX_PATH;
From 6340730427908b839aaa3d00c82497818cec93e1 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 21:59:39 +0000
Subject: [PATCH 067/476] refactor(KeyCounter): remove circularity
---
.../TestSceneOsuTouchInput.cs | 2 +-
osu.Game/Screens/Play/KeyCounter.cs | 52 +++++++++++--------
.../Screens/Play/KeyCounterActionTrigger.cs | 2 +-
.../Screens/Play/KeyCounterKeyboardTrigger.cs | 2 +-
.../Screens/Play/KeyCounterMouseTrigger.cs | 2 +-
5 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 950e034d8f..c73025ebb9 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -593,7 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- Light();
+ LightUp();
}
return false;
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 4a7203870c..3748792383 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -45,7 +46,9 @@ namespace osu.Game.Screens.Play
Trigger = trigger,
};
- Trigger.Target = this;
+ Trigger.OnLightUp += LightUp;
+ Trigger.OnUnlight += Unlight;
+
Name = trigger.Name;
}
@@ -67,37 +70,40 @@ namespace osu.Game.Screens.Play
CountPresses--;
}
+ protected virtual void LightUp(bool increment = true)
+ {
+ IsLit.Value = true;
+ if (increment)
+ Increment();
+ }
+
+ protected virtual void Unlight(bool preserve = true)
+ {
+ IsLit.Value = false;
+ if (!preserve)
+ Decrement();
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+ Trigger.OnLightUp -= LightUp;
+ Trigger.OnUnlight -= Unlight;
+ }
+
public abstract partial class InputTrigger : Component
{
- private KeyCounter? target;
-
- public KeyCounter Target
- {
- set => target = value;
- }
+ public event Action? OnLightUp;
+ public event Action? OnUnlight;
protected InputTrigger(string name)
{
Name = name;
}
- protected void Light(bool increment = true)
- {
- if (target == null) return;
+ protected void LightUp(bool increment = true) => OnLightUp?.Invoke(increment);
- target.IsLit.Value = true;
- if (increment)
- target.Increment();
- }
-
- protected void Unlight(bool preserve = true)
- {
- if (target == null) return;
-
- target.IsLit.Value = false;
- if (!preserve)
- target.Decrement();
- }
+ protected void Unlight(bool preserve = true) => OnUnlight?.Invoke(preserve);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
index 51b82ac5e5..c6acb3f95f 100644
--- a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- Light(forwards);
+ LightUp(forwards);
return false;
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
index fee716abf4..18eb6b7612 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play
{
if (e.Key == Key)
{
- Light();
+ LightUp();
}
return base.OnKeyDown(e);
diff --git a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
index a693db9b19..1446494b5b 100644
--- a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- Light();
+ LightUp();
return base.OnMouseDown(e);
}
From ddd6c1a1c671c24f33479eceff34f7acf05b5cc7 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 22:20:34 +0000
Subject: [PATCH 068/476] refactor(KeyCounter): address bindables issues
`IsCounting` is back being an auto-property.
`countPresses` is now encapsulated and being exposed as an
`IBindable` via `CountPresses`
---
.../Visual/Gameplay/TestSceneAutoplay.cs | 4 ++--
.../Gameplay/TestSceneGameplayRewinding.cs | 4 ++--
.../Visual/Gameplay/TestSceneKeyCounter.cs | 6 +++---
.../Visual/Gameplay/TestSceneReplay.cs | 2 +-
.../TestSceneChangeAndUseGameplayBindings.cs | 4 ++--
osu.Game/Screens/Play/DefaultKeyCounter.cs | 4 ++--
osu.Game/Screens/Play/KeyCounter.cs | 20 +++++--------------
7 files changed, 17 insertions(+), 27 deletions(-)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 5442b3bfef..4b6e1f089f 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -35,14 +35,14 @@ namespace osu.Game.Tests.Visual.Gameplay
var referenceBeatmap = CreateBeatmap(new OsuRuleset().RulesetInfo);
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
- AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
+ AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses.Value > 2));
seekTo(referenceBeatmap.Breaks[0].StartTime);
AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
- AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
+ AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses.Value == 0));
seekTo(referenceBeatmap.HitObjects[^1].GetEndTime());
AddUntilStep("results displayed", () => getResultsScreen()?.IsLoaded == true);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
index 1dffeed01b..9f485cd7bf 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayRewinding.cs
@@ -31,11 +31,11 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("wait for track to start running", () => Beatmap.Value.Track.IsRunning);
addSeekStep(3000);
AddAssert("all judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => h.Judged));
- AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Select(kc => kc.CountPresses).Sum() == 15);
+ AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Select(kc => kc.CountPresses.Value).Sum() == 15);
AddStep("clear results", () => Player.Results.Clear());
addSeekStep(0);
AddAssert("none judged", () => Player.DrawableRuleset.Playfield.AllHitObjects.All(h => !h.Judged));
- AddUntilStep("key counters reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
+ AddUntilStep("key counters reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses.Value == 0));
AddAssert("no results triggered", () => Player.Results.Count == 0);
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 975a5c9465..9eeee800d9 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -46,12 +46,12 @@ namespace osu.Game.Tests.Visual.Gameplay
}
addPressKeyStep();
- AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1);
+ AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 1);
addPressKeyStep();
- AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2);
+ AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 2);
AddStep("Disable counting", () => testCounter.IsCounting = false);
addPressKeyStep();
- AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses == 2);
+ AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses.Value == 2);
Add(kc);
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
index c476aae202..542686f0cd 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplay.cs
@@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay
protected override void AddCheckSteps()
{
AddUntilStep("score above zero", () => ((ScoreAccessibleReplayPlayer)Player).ScoreProcessor.TotalScore.Value > 0);
- AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 0));
+ AddUntilStep("key counter counted keys", () => ((ScoreAccessibleReplayPlayer)Player).HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses.Value > 0));
AddAssert("cannot fail", () => !((ScoreAccessibleReplayPlayer)Player).AllowFail);
}
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
index d937b9e6d7..59a0f9cea8 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
@@ -69,10 +69,10 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("wait for gameplay", () => player?.IsBreakTime.Value == false);
AddStep("press 'z'", () => InputManager.Key(Key.Z));
- AddAssert("key counter didn't increase", () => keyCounter.CountPresses == 0);
+ AddAssert("key counter didn't increase", () => keyCounter.CountPresses.Value == 0);
AddStep("press 's'", () => InputManager.Key(Key.S));
- AddAssert("key counter did increase", () => keyCounter.CountPresses == 1);
+ AddAssert("key counter did increase", () => keyCounter.CountPresses.Value == 1);
}
private KeyBindingsSubsection osuBindingSubsection => keyBindingPanel
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
index 93dc4abcb5..52d54b9d4a 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounter.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -67,7 +67,7 @@ namespace osu.Game.Screens.Play
},
countSpriteText = new OsuSpriteText
{
- Text = CountPresses.ToString(@"#,0"),
+ Text = CountPresses.Value.ToString(@"#,0"),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.Both,
@@ -83,7 +83,7 @@ namespace osu.Game.Screens.Play
Width = buttonSprite.DrawWidth;
IsLit.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
- PressesCount.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
+ CountPresses.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
}
private void updateGlowSprite(bool show)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 3748792383..23afa97597 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -12,28 +12,18 @@ namespace osu.Game.Screens.Play
{
public readonly InputTrigger Trigger;
- protected Bindable IsCountingBindable = new BindableBool(true);
-
private readonly Container content;
protected override Container Content => content;
- protected Bindable PressesCount = new BindableInt
+ private readonly Bindable countPresses = new BindableInt
{
MinValue = 0
};
- public bool IsCounting
- {
- get => IsCountingBindable.Value;
- set => IsCountingBindable.Value = value;
- }
+ public bool IsCounting { get; set; } = true;
- public int CountPresses
- {
- get => PressesCount.Value;
- private set => PressesCount.Value = value;
- }
+ public IBindable CountPresses => countPresses;
protected KeyCounter(InputTrigger trigger)
{
@@ -59,7 +49,7 @@ namespace osu.Game.Screens.Play
if (!IsCounting)
return;
- CountPresses++;
+ countPresses.Value++;
}
public void Decrement()
@@ -67,7 +57,7 @@ namespace osu.Game.Screens.Play
if (!IsCounting)
return;
- CountPresses--;
+ countPresses.Value--;
}
protected virtual void LightUp(bool increment = true)
From 6cb00cd42f22b7324df66a2863a0fe333875d2f8 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 01:44:45 +0300
Subject: [PATCH 069/476] Add more test cases
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 54 ++++++++++++++++---
1 file changed, 48 insertions(+), 6 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index c464eb5c28..c67ec75e92 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Tests.Database
}
[Test]
- public void ExportFileWithNormalName()
+ public void ExportFileWithNormalNameTest()
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
@@ -30,23 +30,65 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(filename);
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
- Assert.DoesNotThrow(() => legacyExporter?.Export(item));
- Assert.That(exportStorage?.Exists($"{filename}{legacyExporter?.GetExtension()}"), Is.True);
+ exportItemWithLongNameAndAssert(item, exportStorage, filename);
}
[Test]
- public void ExportFileWithSuperLongName()
+ public void ExportFileWithNormalNameMultipleTimesTest()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ const string filename = "normal file name";
+ var item = new TestPathInfo(filename);
+
+ Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+
+ //Export multiple times
+ string expectedFileName;
+ for (int i = 0; i < 10; i++)
+ {
+ expectedFileName = i == 0 ? filename : $"{filename} ({i})";
+ exportItemWithLongNameAndAssert(item, exportStorage, expectedFileName);
+ }
+ }
+
+ [Test]
+ public void ExportFileWithSuperLongNameTest()
{
var exportStorage = storage?.GetStorageForDirectory(@"exports");
const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int capacity = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
- string expectedName = fullname.Remove(capacity);
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ }
+
+ [Test]
+ public void ExportFileWithSuperLongNameMultipleTimesTest()
+ {
+ var exportStorage = storage?.GetStorageForDirectory(@"exports");
+
+ const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ string expectedName = fullname.Remove(expectedLength);
+
+ var item = new TestPathInfo(fullname);
+
+ Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+
+ //Export multiple times
+ for (int i = 0; i < 10; i++)
+ exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ }
+
+ private void exportItemWithLongNameAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
+ {
Assert.DoesNotThrow(() => legacyExporter?.Export(item));
Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
}
From 1d8b348e4c72d29d44ce0f56d9d6e71f98000187 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 01:46:15 +0300
Subject: [PATCH 070/476] Improve naming
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index c67ec75e92..97b32b0c51 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(filename);
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
- exportItemWithLongNameAndAssert(item, exportStorage, filename);
+ exportItemAndAssert(item, exportStorage, filename);
}
[Test]
@@ -48,7 +48,7 @@ namespace osu.Game.Tests.Database
for (int i = 0; i < 10; i++)
{
expectedFileName = i == 0 ? filename : $"{filename} ({i})";
- exportItemWithLongNameAndAssert(item, exportStorage, expectedFileName);
+ exportItemAndAssert(item, exportStorage, expectedFileName);
}
}
@@ -65,7 +65,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(fullname);
Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
- exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, exportStorage, expectedName);
}
[Test]
@@ -84,10 +84,10 @@ namespace osu.Game.Tests.Database
//Export multiple times
for (int i = 0; i < 10; i++)
- exportItemWithLongNameAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, exportStorage, expectedName);
}
- private void exportItemWithLongNameAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
+ private void exportItemAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
{
Assert.DoesNotThrow(() => legacyExporter?.Export(item));
Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
From f4038a49a17f8670f3b3ed8613e12d197d4e96b6 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 01:50:24 +0300
Subject: [PATCH 071/476] Fix inspectCode issues
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 97b32b0c51..d67cb8abf1 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -44,10 +44,9 @@ namespace osu.Game.Tests.Database
Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
//Export multiple times
- string expectedFileName;
for (int i = 0; i < 10; i++)
{
- expectedFileName = i == 0 ? filename : $"{filename} ({i})";
+ string expectedFileName = i == 0 ? filename : $"{filename} ({i})";
exportItemAndAssert(item, exportStorage, expectedFileName);
}
}
From c61fac578ca53fa4dba22ac7ec85aa0cc335c762 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 23:15:03 +0000
Subject: [PATCH 072/476] style(KeyCounter): rename methods and arguments
As for the second suggestion in
https://github.com/ppy/osu/pull/22654#discussion_r1109047998,
I went with the first one as only one Trigger actually uses this
argument for rewinding.
---
.../TestSceneOsuTouchInput.cs | 4 ++--
osu.Game/Screens/Play/KeyCounter.cs | 20 +++++++++----------
.../Screens/Play/KeyCounterActionTrigger.cs | 4 ++--
.../Screens/Play/KeyCounterKeyboardTrigger.cs | 4 ++--
.../Screens/Play/KeyCounterMouseTrigger.cs | 4 ++--
5 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index c73025ebb9..8a933c6b24 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -593,7 +593,7 @@ namespace osu.Game.Rulesets.Osu.Tests
{
if (e.Action == Action)
{
- LightUp();
+ Activate();
}
return false;
@@ -602,7 +602,7 @@ namespace osu.Game.Rulesets.Osu.Tests
public void OnReleased(KeyBindingReleaseEvent e)
{
if (e.Action == Action)
- Unlight();
+ Deactivate();
}
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 23afa97597..a276c9d59e 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -36,8 +36,8 @@ namespace osu.Game.Screens.Play
Trigger = trigger,
};
- Trigger.OnLightUp += LightUp;
- Trigger.OnUnlight += Unlight;
+ Trigger.OnActivate += Activate;
+ Trigger.OnDeactivate += Deactivate;
Name = trigger.Name;
}
@@ -60,14 +60,14 @@ namespace osu.Game.Screens.Play
countPresses.Value--;
}
- protected virtual void LightUp(bool increment = true)
+ protected virtual void Activate(bool increment = true)
{
IsLit.Value = true;
if (increment)
Increment();
}
- protected virtual void Unlight(bool preserve = true)
+ protected virtual void Deactivate(bool preserve = true)
{
IsLit.Value = false;
if (!preserve)
@@ -77,23 +77,23 @@ namespace osu.Game.Screens.Play
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
- Trigger.OnLightUp -= LightUp;
- Trigger.OnUnlight -= Unlight;
+ Trigger.OnActivate -= Activate;
+ Trigger.OnDeactivate -= Deactivate;
}
public abstract partial class InputTrigger : Component
{
- public event Action? OnLightUp;
- public event Action? OnUnlight;
+ public event Action? OnActivate;
+ public event Action? OnDeactivate;
protected InputTrigger(string name)
{
Name = name;
}
- protected void LightUp(bool increment = true) => OnLightUp?.Invoke(increment);
+ protected void Activate(bool forwardPlayback = true) => OnActivate?.Invoke(forwardPlayback);
- protected void Unlight(bool preserve = true) => OnUnlight?.Invoke(preserve);
+ protected void Deactivate(bool forwardPlayback = true) => OnDeactivate?.Invoke(forwardPlayback);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
index c6acb3f95f..8bb9bdc886 100644
--- a/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterActionTrigger.cs
@@ -23,7 +23,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return false;
- LightUp(forwards);
+ Activate(forwards);
return false;
}
@@ -32,7 +32,7 @@ namespace osu.Game.Screens.Play
if (!EqualityComparer.Default.Equals(action, Action))
return;
- Unlight(forwards);
+ Deactivate(forwards);
}
}
}
diff --git a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
index 18eb6b7612..56c5ab0083 100644
--- a/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterKeyboardTrigger.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play
{
if (e.Key == Key)
{
- LightUp();
+ Activate();
}
return base.OnKeyDown(e);
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.Play
protected override void OnKeyUp(KeyUpEvent e)
{
if (e.Key == Key)
- Unlight();
+ Deactivate();
base.OnKeyUp(e);
}
diff --git a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
index 1446494b5b..66890073a8 100644
--- a/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
+++ b/osu.Game/Screens/Play/KeyCounterMouseTrigger.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Screens.Play
protected override bool OnMouseDown(MouseDownEvent e)
{
if (e.Button == Button)
- LightUp();
+ Activate();
return base.OnMouseDown(e);
}
@@ -47,7 +47,7 @@ namespace osu.Game.Screens.Play
protected override void OnMouseUp(MouseUpEvent e)
{
if (e.Button == Button)
- Unlight();
+ Deactivate();
base.OnMouseUp(e);
}
From e3ca751027af079ac74e73ad7e88d59c8dc82d24 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Thu, 16 Feb 2023 23:17:47 +0000
Subject: [PATCH 073/476] refactor: make `FillFlowContainer` read-only
---
osu.Game/Screens/Play/KeyCounterDisplay.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index ed47af11a3..0f2f8e43c9 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -17,7 +17,7 @@ namespace osu.Game.Screens.Play
{
protected readonly Bindable ConfigVisibility = new Bindable();
- protected FillFlowContainer KeyFlow = new FillFlowContainer();
+ protected readonly FillFlowContainer KeyFlow = new FillFlowContainer();
protected override Container Content => KeyFlow;
From 6193aeed120f2bc85768a47efafa21b95695119e Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 00:13:45 +0000
Subject: [PATCH 074/476] fix(TestSceneOsuTouchInput): missing Value call
---
osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
index 8a933c6b24..4cb017cc56 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOsuTouchInput.cs
@@ -562,8 +562,8 @@ namespace osu.Game.Rulesets.Osu.Tests
private void assertKeyCounter(int left, int right)
{
- AddAssert($"The left key was pressed {left} times", () => leftKeyCounter.CountPresses, () => Is.EqualTo(left));
- AddAssert($"The right key was pressed {right} times", () => rightKeyCounter.CountPresses, () => Is.EqualTo(right));
+ AddAssert($"The left key was pressed {left} times", () => leftKeyCounter.CountPresses.Value, () => Is.EqualTo(left));
+ AddAssert($"The right key was pressed {right} times", () => rightKeyCounter.CountPresses.Value, () => Is.EqualTo(right));
}
private void releaseAllTouches()
From d0e8d65766df488c98bf99ccdef7c05df3f694d8 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 00:40:01 +0000
Subject: [PATCH 075/476] style(KeyCounter): rename `IsLit` to `IsActive`
---
osu.Game/Screens/Play/DefaultKeyCounter.cs | 2 +-
osu.Game/Screens/Play/KeyCounter.cs | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounter.cs b/osu.Game/Screens/Play/DefaultKeyCounter.cs
index 52d54b9d4a..3673281577 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounter.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounter.cs
@@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play
Height = buttonSprite.DrawHeight;
Width = buttonSprite.DrawWidth;
- IsLit.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
+ IsActive.BindValueChanged(e => updateGlowSprite(e.NewValue), true);
CountPresses.BindValueChanged(e => countSpriteText.Text = e.NewValue.ToString(@"#,0"), true);
}
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a276c9d59e..212843cbe9 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -42,7 +42,7 @@ namespace osu.Game.Screens.Play
Name = trigger.Name;
}
- protected Bindable IsLit = new BindableBool();
+ protected Bindable IsActive = new BindableBool();
public void Increment()
{
@@ -62,14 +62,14 @@ namespace osu.Game.Screens.Play
protected virtual void Activate(bool increment = true)
{
- IsLit.Value = true;
+ IsActive.Value = true;
if (increment)
Increment();
}
protected virtual void Deactivate(bool preserve = true)
{
- IsLit.Value = false;
+ IsActive.Value = false;
if (!preserve)
Decrement();
}
From 415220a44769fa8a7027ec8d56eb38b63fac6e04 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:30:00 +0900
Subject: [PATCH 076/476] Tidy up new test method code quality
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 55 +++++++++++--------
1 file changed, 31 insertions(+), 24 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index d67cb8abf1..803cd40132 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using NUnit.Framework;
+using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Platform;
using osu.Framework.Testing;
using osu.Game.Database;
@@ -11,11 +12,11 @@ namespace osu.Game.Tests.Database
{
public class LegacyExporterTest
{
- private TestLegacyExporter? legacyExporter;
- private TemporaryNativeStorage? storage;
+ private TestLegacyExporter legacyExporter = null!;
+ private TemporaryNativeStorage storage = null!;
[SetUp]
- public void SetupLegacyExporter()
+ public void SetUp()
{
storage = new TemporaryNativeStorage("export-storage");
legacyExporter = new TestLegacyExporter(storage);
@@ -24,24 +25,24 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithNormalNameTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
exportItemAndAssert(item, exportStorage, filename);
}
[Test]
public void ExportFileWithNormalNameMultipleTimesTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.FileName.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -54,59 +55,65 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithSuperLongNameTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ const string fullname =
+ "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
exportItemAndAssert(item, exportStorage, expectedName);
}
[Test]
public void ExportFileWithSuperLongNameMultipleTimesTest()
{
- var exportStorage = storage?.GetStorageForDirectory(@"exports");
+ var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname = "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ const string fullname =
+ "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter?.GetExtension().Length ?? 0);
+ int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.FileName.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
exportItemAndAssert(item, exportStorage, expectedName);
}
- private void exportItemAndAssert(IHasNamedFiles item, Storage? exportStorage, string expectedName)
+ private void exportItemAndAssert(IHasNamedFiles item, Storage exportStorage, string expectedName)
{
- Assert.DoesNotThrow(() => legacyExporter?.Export(item));
- Assert.That(exportStorage?.Exists($"{expectedName}{legacyExporter?.GetExtension()}"), Is.True);
+ Assert.DoesNotThrow(() => legacyExporter.Export(item));
+ Assert.That(exportStorage.Exists($"{expectedName}{legacyExporter.GetExtension()}"), Is.True);
}
[TearDown]
- public void CleanupAfterTest()
+ public void TearDown()
{
- storage?.Dispose();
+ if (storage.IsNotNull())
+ storage.Dispose();
}
private class TestPathInfo : IHasNamedFiles
{
- public string FileName { get; set; }
+ public string Filename { get; }
- public TestPathInfo(string fileName) => FileName = fileName;
+ public IEnumerable Files { get; } = new List();
- public IEnumerable Files { get; set; } = new List();
+ public TestPathInfo(string filename)
+ {
+ Filename = filename;
+ }
- public override string ToString() => FileName;
+ public override string ToString() => Filename;
}
private class TestLegacyExporter : LegacyExporter
From 96b1498932c4b93126a477cf1acc1b93d11c1b57 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:33:22 +0900
Subject: [PATCH 077/476] Rename max length variable to make sense (it's a
filename limit, not path)
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 14 +++++++-------
osu.Game/Database/LegacyExporter.cs | 12 +++++++-----
2 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 803cd40132..6f144ee833 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -30,7 +30,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.GetMaxPathLength()));
exportItemAndAssert(item, exportStorage, filename);
}
@@ -42,7 +42,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPathLength(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -60,12 +60,12 @@ namespace osu.Game.Tests.Database
const string fullname =
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
+ int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
exportItemAndAssert(item, exportStorage, expectedName);
}
@@ -77,12 +77,12 @@ namespace osu.Game.Tests.Database
const string fullname =
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
- int expectedLength = TestLegacyExporter.GetMaxPath() - (legacyExporter.GetExtension().Length);
+ int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
string expectedName = fullname.Remove(expectedLength);
var item = new TestPathInfo(fullname);
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPath(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -123,7 +123,7 @@ namespace osu.Game.Tests.Database
{
}
- public static int GetMaxPath() => MAX_PATH;
+ public static int GetMaxPathLength() => MAX_FILENAME_LENGTH;
public string GetExtension() => FileExtension;
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 9041f58368..1b74454027 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -21,12 +21,14 @@ namespace osu.Game.Database
where TModel : class, IHasNamedFiles
{
///
- /// Max length of filename (including extension)
+ /// Max length of filename (including extension).
///
///
- /// This constant is smaller 256 because adds additional "_" to the end of the path
+ /// TODO: WHY? DOCUMENTATION PER PLATFORM LINKS HERE.
+ ///
+ /// This actual usable length is smaller 256 because adds additional "_" to the end of the path
///
- protected const int MAX_PATH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ protected const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
///
/// The file extension for exports (including the leading '.').
@@ -60,11 +62,11 @@ namespace osu.Game.Database
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- if (filename.Length > MAX_PATH)
+ if (filename.Length > MAX_FILENAME_LENGTH)
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
- filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_PATH - FileExtension.Length); //Truncating the name to fit the path limit
+ filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); //Truncating the name to fit the path limit
filename = $"{filenameWithoutExtension}{FileExtension}";
}
From 8c772a723f0f8ae52cf3141fab286c64c2eba198 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:34:19 +0900
Subject: [PATCH 078/476] Expose constant `public`ly rather than reexposing
business
---
osu.Game/Database/LegacyExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 1b74454027..7434a46602 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -28,7 +28,7 @@ namespace osu.Game.Database
///
/// This actual usable length is smaller 256 because adds additional "_" to the end of the path
///
- protected const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
///
/// The file extension for exports (including the leading '.').
From 99236f0ae80399d9fade78c7331dff63d59301e4 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:39:24 +0900
Subject: [PATCH 079/476] Move long filename to fixture level
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 31 ++++++++-----------
1 file changed, 13 insertions(+), 18 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 6f144ee833..114872bcf8 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -15,6 +15,9 @@ namespace osu.Game.Tests.Database
private TestLegacyExporter legacyExporter = null!;
private TemporaryNativeStorage storage = null!;
+ private const string long_filename =
+ "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+
[SetUp]
public void SetUp()
{
@@ -30,7 +33,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.GetMaxPathLength()));
+ Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
exportItemAndAssert(item, exportStorage, filename);
}
@@ -42,7 +45,7 @@ namespace osu.Game.Tests.Database
const string filename = "normal file name";
var item = new TestPathInfo(filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.GetMaxPathLength(), Is.True);
+ Assert.That(item.Filename.Length < TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -57,15 +60,12 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname =
- "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
+ string expectedName = long_filename.Remove(expectedLength);
- int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
- string expectedName = fullname.Remove(expectedLength);
+ var item = new TestPathInfo(long_filename);
- var item = new TestPathInfo(fullname);
-
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
exportItemAndAssert(item, exportStorage, expectedName);
}
@@ -74,15 +74,12 @@ namespace osu.Game.Tests.Database
{
var exportStorage = storage.GetStorageForDirectory(@"exports");
- const string fullname =
- "some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
+ int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
+ string expectedName = long_filename.Remove(expectedLength);
- int expectedLength = TestLegacyExporter.GetMaxPathLength() - (legacyExporter.GetExtension().Length);
- string expectedName = fullname.Remove(expectedLength);
+ var item = new TestPathInfo(long_filename);
- var item = new TestPathInfo(fullname);
-
- Assert.That(item.Filename.Length > TestLegacyExporter.GetMaxPathLength(), Is.True);
+ Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
//Export multiple times
for (int i = 0; i < 10; i++)
@@ -123,8 +120,6 @@ namespace osu.Game.Tests.Database
{
}
- public static int GetMaxPathLength() => MAX_FILENAME_LENGTH;
-
public string GetExtension() => FileExtension;
protected override string FileExtension => ".ots";
From 4560ae6b026bd1ce575713ccab7d9052f73af40b Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:39:31 +0900
Subject: [PATCH 080/476] Mark test as fixture
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 1 +
1 file changed, 1 insertion(+)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index 114872bcf8..ec20028a2c 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -10,6 +10,7 @@ using osu.Game.Database;
namespace osu.Game.Tests.Database
{
+ [TestFixture]
public class LegacyExporterTest
{
private TestLegacyExporter legacyExporter = null!;
From 86d110e893cd2572377c575fc67e5260a1199e27 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:43:42 +0900
Subject: [PATCH 081/476] Simplify test storage by removing nested storage
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 20 ++++++-------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index ec20028a2c..f38ffb7db6 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -29,20 +29,16 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithNormalNameTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
const string filename = "normal file name";
var item = new TestPathInfo(filename);
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
- exportItemAndAssert(item, exportStorage, filename);
+ exportItemAndAssert(item, filename);
}
[Test]
public void ExportFileWithNormalNameMultipleTimesTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
const string filename = "normal file name";
var item = new TestPathInfo(filename);
@@ -52,29 +48,25 @@ namespace osu.Game.Tests.Database
for (int i = 0; i < 10; i++)
{
string expectedFileName = i == 0 ? filename : $"{filename} ({i})";
- exportItemAndAssert(item, exportStorage, expectedFileName);
+ exportItemAndAssert(item, expectedFileName);
}
}
[Test]
public void ExportFileWithSuperLongNameTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
string expectedName = long_filename.Remove(expectedLength);
var item = new TestPathInfo(long_filename);
Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
- exportItemAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, expectedName);
}
[Test]
public void ExportFileWithSuperLongNameMultipleTimesTest()
{
- var exportStorage = storage.GetStorageForDirectory(@"exports");
-
int expectedLength = TestLegacyExporter.MAX_FILENAME_LENGTH - (legacyExporter.GetExtension().Length);
string expectedName = long_filename.Remove(expectedLength);
@@ -84,13 +76,13 @@ namespace osu.Game.Tests.Database
//Export multiple times
for (int i = 0; i < 10; i++)
- exportItemAndAssert(item, exportStorage, expectedName);
+ exportItemAndAssert(item, expectedName);
}
- private void exportItemAndAssert(IHasNamedFiles item, Storage exportStorage, string expectedName)
+ private void exportItemAndAssert(IHasNamedFiles item, string expectedName)
{
Assert.DoesNotThrow(() => legacyExporter.Export(item));
- Assert.That(exportStorage.Exists($"{expectedName}{legacyExporter.GetExtension()}"), Is.True);
+ Assert.That(storage.Exists($"exports/{expectedName}{legacyExporter.GetExtension()}"), Is.True);
}
[TearDown]
From 8ef3fb26e056b2c271a690be5539983f6d9d09b0 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:45:27 +0900
Subject: [PATCH 082/476] More constants and assert fixes
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index f38ffb7db6..b8dca6dc7b 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -16,6 +16,8 @@ namespace osu.Game.Tests.Database
private TestLegacyExporter legacyExporter = null!;
private TemporaryNativeStorage storage = null!;
+ private const string short_filename = "normal file name";
+
private const string long_filename =
"some file with super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name super long name";
@@ -29,25 +31,24 @@ namespace osu.Game.Tests.Database
[Test]
public void ExportFileWithNormalNameTest()
{
- const string filename = "normal file name";
- var item = new TestPathInfo(filename);
+ var item = new TestPathInfo(short_filename);
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
- exportItemAndAssert(item, filename);
+
+ exportItemAndAssert(item, short_filename);
}
[Test]
public void ExportFileWithNormalNameMultipleTimesTest()
{
- const string filename = "normal file name";
- var item = new TestPathInfo(filename);
+ var item = new TestPathInfo(short_filename);
- Assert.That(item.Filename.Length < TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
+ Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
for (int i = 0; i < 10; i++)
{
- string expectedFileName = i == 0 ? filename : $"{filename} ({i})";
+ string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})";
exportItemAndAssert(item, expectedFileName);
}
}
@@ -60,7 +61,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(long_filename);
- Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
+ Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
exportItemAndAssert(item, expectedName);
}
@@ -72,7 +73,7 @@ namespace osu.Game.Tests.Database
var item = new TestPathInfo(long_filename);
- Assert.That(item.Filename.Length > TestLegacyExporter.MAX_FILENAME_LENGTH, Is.True);
+ Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
for (int i = 0; i < 10; i++)
From 372b6b794cae69dc16a882f0caa3b91dcfef0491 Mon Sep 17 00:00:00 2001
From: Dean Herbert
Date: Fri, 17 Feb 2023 13:45:43 +0900
Subject: [PATCH 083/476] I don't know what .ots is but let's not use random
file extension that make no sense
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index b8dca6dc7b..c9aea80585 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -116,7 +116,7 @@ namespace osu.Game.Tests.Database
public string GetExtension() => FileExtension;
- protected override string FileExtension => ".ots";
+ protected override string FileExtension => ".test";
}
}
}
From c94e647e21902db2fc98bc3a42ad1b2a75246842 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 09:09:56 +0000
Subject: [PATCH 084/476] style(KeyCounterDisplay): remove type check
---
osu.Game/Screens/Play/KeyCounterDisplay.cs | 5 -----
1 file changed, 5 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounterDisplay.cs b/osu.Game/Screens/Play/KeyCounterDisplay.cs
index 0f2f8e43c9..d2b50ff73d 100644
--- a/osu.Game/Screens/Play/KeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/KeyCounterDisplay.cs
@@ -29,15 +29,10 @@ namespace osu.Game.Screens.Play
public override void Add(KeyCounter key)
{
- if (!CheckType(key))
- throw new ArgumentException($"{key.GetType()} is not a supported {nameof(KeyCounter)}.", nameof(key));
-
base.Add(key);
key.IsCounting = IsCounting;
}
- protected virtual bool CheckType(KeyCounter key) => true;
-
[BackgroundDependencyLoader]
private void load(OsuConfigManager config)
{
From 8830e0658834095dd87e3d9b82b425528021b93a Mon Sep 17 00:00:00 2001
From: tsrk
Date: Fri, 17 Feb 2023 09:17:11 +0000
Subject: [PATCH 085/476] fix: compilation
---
osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index b69ecfd7ae..fbf1b87395 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -49,8 +49,6 @@ namespace osu.Game.Screens.Play
defaultKey.KeyUpTextColor = KeyUpTextColor;
}
- protected override bool CheckType(KeyCounter key) => key is DefaultKeyCounter;
-
protected override void UpdateVisibility() =>
// Isolate changing visibility of the key counters from fading this component.
KeyFlow.FadeTo(AlwaysVisible.Value || ConfigVisibility.Value ? 1 : 0, duration);
From ceed3606cd7a3b0666c345ea768219ac5e65b91d Mon Sep 17 00:00:00 2001
From: Cootz <50776304+Cootz@users.noreply.github.com>
Date: Fri, 17 Feb 2023 13:46:06 +0300
Subject: [PATCH 086/476] Remove redundant comment
Co-authored-by: Dean Herbert
---
osu.Game/Database/LegacyExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 7434a46602..7fe0428db3 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -66,7 +66,7 @@ namespace osu.Game.Database
{
string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
- filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length); //Truncating the name to fit the path limit
+ filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
filename = $"{filenameWithoutExtension}{FileExtension}";
}
From a3b440493aeae5fc3fbea99e36be28758c8fe2ba Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 15:23:43 +0300
Subject: [PATCH 087/476] Update xml doc
---
osu.Game/Database/LegacyExporter.cs | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 7fe0428db3..2d0a1d3528 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -24,9 +24,18 @@ namespace osu.Game.Database
/// Max length of filename (including extension).
///
///
- /// TODO: WHY? DOCUMENTATION PER PLATFORM LINKS HERE.
- ///
- /// This actual usable length is smaller 256 because adds additional "_" to the end of the path
+ ///
+ /// Filename limit for most OSs is 255, this actual usable length is smaller because adds additional "_" to the end of the path.
+ ///
+ ///
+ /// For more information see:
+ ///
+ /// File specification syntax
+ ///
+ ///
+ /// File systems limitations
+ ///
+ ///
///
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
From fd1beaef87ef2156b5f5e56bf6d1656ece326a16 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 15:24:27 +0300
Subject: [PATCH 088/476] Fix typo
---
osu.Game/Database/LegacyExporter.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 2d0a1d3528..04d5a3aebc 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -25,7 +25,7 @@ namespace osu.Game.Database
///
///
///
- /// Filename limit for most OSs is 255, this actual usable length is smaller because adds additional "_" to the end of the path.
+ /// The filename limit for most OSs is 255. This actual usable length is smaller because adds an additional "_" to the end of the path.
///
///
/// For more information see:
From e3bdb3d852a85748032ea468d1763849aee74249 Mon Sep 17 00:00:00 2001
From: Cootz
Date: Fri, 17 Feb 2023 15:32:36 +0300
Subject: [PATCH 089/476] Align links in one line
---
osu.Game/Database/LegacyExporter.cs | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index 04d5a3aebc..cf88efb151 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -28,13 +28,7 @@ namespace osu.Game.Database
/// The filename limit for most OSs is 255. This actual usable length is smaller because adds an additional "_" to the end of the path.
///
///
- /// For more information see:
- ///
- /// File specification syntax
- ///
- ///
- /// File systems limitations
- ///
+ /// For more information see file specification syntax, file systems limitations
///
///
public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
From 90aa4288d0a9a265d666c8e66545108bce4d8edd Mon Sep 17 00:00:00 2001
From: Cootz
Date: Tue, 21 Feb 2023 18:35:53 +0300
Subject: [PATCH 090/476] Reduce the allowed length by 5 to account for (99)
suffix. Move truncating logic to `GetFilename`. Update tests.
---
osu.Game.Tests/Database/LegacyExporterTest.cs | 9 ++++++---
osu.Game/Database/LegacyExporter.cs | 20 +++++++++----------
2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/osu.Game.Tests/Database/LegacyExporterTest.cs b/osu.Game.Tests/Database/LegacyExporterTest.cs
index c9aea80585..d41b3a5017 100644
--- a/osu.Game.Tests/Database/LegacyExporterTest.cs
+++ b/osu.Game.Tests/Database/LegacyExporterTest.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Tests.Database
Assert.That(item.Filename.Length, Is.LessThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
- for (int i = 0; i < 10; i++)
+ for (int i = 0; i < 100; i++)
{
string expectedFileName = i == 0 ? short_filename : $"{short_filename} ({i})";
exportItemAndAssert(item, expectedFileName);
@@ -76,8 +76,11 @@ namespace osu.Game.Tests.Database
Assert.That(item.Filename.Length, Is.GreaterThan(TestLegacyExporter.MAX_FILENAME_LENGTH));
//Export multiple times
- for (int i = 0; i < 10; i++)
- exportItemAndAssert(item, expectedName);
+ for (int i = 0; i < 100; i++)
+ {
+ string expectedFilename = i == 0 ? expectedName : $"{expectedName} ({i})";
+ exportItemAndAssert(item, expectedFilename);
+ }
}
private void exportItemAndAssert(IHasNamedFiles item, string expectedName)
diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs
index cf88efb151..0fa7b9e03c 100644
--- a/osu.Game/Database/LegacyExporter.cs
+++ b/osu.Game/Database/LegacyExporter.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Database
/// For more information see file specification syntax, file systems limitations
///
///
- public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars)
+ public const int MAX_FILENAME_LENGTH = 255 - (32 + 4 + 2 + 5); //max path - (Guid + Guid "D" format chars + Storage.CreateFileSafely chars + account for ' (99)' suffix)
///
/// The file extension for exports (including the leading '.').
@@ -48,7 +48,15 @@ namespace osu.Game.Database
UserFileStorage = storage.GetStorageForDirectory(@"files");
}
- protected virtual string GetFilename(TModel item) => item.GetDisplayString();
+ protected virtual string GetFilename(TModel item)
+ {
+ string filename = item.GetDisplayString();
+
+ if (filename.Length > MAX_FILENAME_LENGTH - FileExtension.Length)
+ return filename.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
+
+ return filename;
+ }
///
/// Exports an item to a legacy (.zip based) package.
@@ -65,14 +73,6 @@ namespace osu.Game.Database
string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{FileExtension}");
- if (filename.Length > MAX_FILENAME_LENGTH)
- {
- string filenameWithoutExtension = Path.GetFileNameWithoutExtension(filename);
-
- filenameWithoutExtension = filenameWithoutExtension.Remove(MAX_FILENAME_LENGTH - FileExtension.Length);
- filename = $"{filenameWithoutExtension}{FileExtension}";
- }
-
using (var stream = exportStorage.CreateFileSafely(filename))
ExportModelTo(item, stream);
From fc3d74472cc52b6e06cd1c0791f7277d7ed77744 Mon Sep 17 00:00:00 2001
From: Salman Ahmed
Date: Tue, 21 Feb 2023 15:55:46 +0300
Subject: [PATCH 091/476] Add mobile local framework reference support
---
UseLocalFramework.ps1 | 48 ++++++++++++++++++++++++++++++++++++++-----
UseLocalFramework.sh | 39 +++++++++++++++++++++++++++++------
2 files changed, 76 insertions(+), 11 deletions(-)
diff --git a/UseLocalFramework.ps1 b/UseLocalFramework.ps1
index 837685f310..9f4547d980 100644
--- a/UseLocalFramework.ps1
+++ b/UseLocalFramework.ps1
@@ -3,15 +3,53 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
-$CSPROJ="osu.Game/osu.Game.csproj"
+$GAME_CSPROJ="osu.Game/osu.Game.csproj"
+$ANDROID_PROPS="osu.Android.props"
+$IOS_PROPS="osu.iOS.props"
$SLN="osu.sln"
-dotnet remove $CSPROJ package ppy.osu.Framework;
-dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj;
-dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet remove $GAME_CSPROJ reference ppy.osu.Framework;
+dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android;
+dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS;
+
+dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj `
+ ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj `
+ ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj `
+ ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
+
+dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj;
+dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj;
+dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
+
+# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
+(Get-Content "osu.Android.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.Android.props"
+(Get-Content "osu.iOS.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.iOS.props"
+
+# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
+# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
+(Get-Content "osu.iOS.props") |
+ Foreach-Object {
+ if ($_ -match "")
+ {
+ " "
+ }
+
+ $_
+ } | Set-Content "osu.iOS.props"
+
+$TMP=New-TemporaryFile
$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json
-$TMP=New-TemporaryFile
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj")
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force
+
+$SLNF=Get-Content "osu.Android.slnf" | ConvertFrom-Json
+$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj")
+ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
+Move-Item -Path $TMP -Destination "osu.Android.slnf" -Force
+
+$SLNF=Get-Content "osu.iOS.slnf" | ConvertFrom-Json
+$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj")
+ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
+Move-Item -Path $TMP -Destination "osu.iOS.slnf" -Force
diff --git a/UseLocalFramework.sh b/UseLocalFramework.sh
index 4fd1fdfd1b..c12b388e96 100755
--- a/UseLocalFramework.sh
+++ b/UseLocalFramework.sh
@@ -5,14 +5,41 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
-CSPROJ="osu.Game/osu.Game.csproj"
+GAME_CSPROJ="osu.Game/osu.Game.csproj"
+ANDROID_PROPS="osu.Android.props"
+IOS_PROPS="osu.iOS.props"
SLN="osu.sln"
-dotnet remove $CSPROJ package ppy.osu.Framework
-dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj
-dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet remove $GAME_CSPROJ reference ppy.osu.Framework
+dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android
+dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS
+
+dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj \
+ ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj \
+ ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj \
+ ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
+
+dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
+dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj
+dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
+
+# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
+sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.Android.props && rm osu.Android.props.bak
+sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.iOS.props && rm osu.iOS.props.bak
+
+# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
+# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
+sed -i.bak '/<\/Project>/i\
+ \
+' ./osu.iOS.props && rm osu.iOS.props.bak
-SLNF="osu.Desktop.slnf"
tmp=$(mktemp)
+
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp
-mv -f $tmp $SLNF
+mv -f $tmp osu.Desktop.slnf
+
+jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj"]' osu.Android.slnf > $tmp
+mv -f $tmp osu.Android.slnf
+
+jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj"]' osu.iOS.slnf > $tmp
+mv -f $tmp osu.iOS.slnf
From 5bec2d7c525fac4fd975f0abb3e5fd19a37ef843 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Tue, 21 Feb 2023 19:02:56 +0000
Subject: [PATCH 092/476] style(KeyCounter): `forwardPlayback`
---
osu.Game/Screens/Play/KeyCounter.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index 212843cbe9..a07c650736 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -60,17 +60,17 @@ namespace osu.Game.Screens.Play
countPresses.Value--;
}
- protected virtual void Activate(bool increment = true)
+ protected virtual void Activate(bool forwardPlayback = true)
{
IsActive.Value = true;
- if (increment)
+ if (forwardPlayback)
Increment();
}
- protected virtual void Deactivate(bool preserve = true)
+ protected virtual void Deactivate(bool forwardPlayback = true)
{
IsActive.Value = false;
- if (!preserve)
+ if (!forwardPlayback)
Decrement();
}
From 42a5a06b9d6e8e1416c2aaf828dfe236e9617b6e Mon Sep 17 00:00:00 2001
From: tsrk
Date: Tue, 21 Feb 2023 19:10:37 +0000
Subject: [PATCH 093/476] style(KeyCounter): fields and methods visiblity
---
osu.Game/Screens/Play/KeyCounter.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/osu.Game/Screens/Play/KeyCounter.cs b/osu.Game/Screens/Play/KeyCounter.cs
index a07c650736..4bad6920e3 100644
--- a/osu.Game/Screens/Play/KeyCounter.cs
+++ b/osu.Game/Screens/Play/KeyCounter.cs
@@ -42,9 +42,9 @@ namespace osu.Game.Screens.Play
Name = trigger.Name;
}
- protected Bindable IsActive = new BindableBool();
+ protected readonly Bindable IsActive = new BindableBool();
- public void Increment()
+ private void increment()
{
if (!IsCounting)
return;
@@ -52,7 +52,7 @@ namespace osu.Game.Screens.Play
countPresses.Value++;
}
- public void Decrement()
+ private void decrement()
{
if (!IsCounting)
return;
@@ -64,14 +64,14 @@ namespace osu.Game.Screens.Play
{
IsActive.Value = true;
if (forwardPlayback)
- Increment();
+ increment();
}
protected virtual void Deactivate(bool forwardPlayback = true)
{
IsActive.Value = false;
if (!forwardPlayback)
- Decrement();
+ decrement();
}
protected override void Dispose(bool isDisposing)
From 1beec7103725ca9ade4b081804d8a7cc83e5c912 Mon Sep 17 00:00:00 2001
From: tsrk
Date: Wed, 22 Feb 2023 14:58:27 +0000
Subject: [PATCH 094/476] refactor(KeyCounterDisplay): apply suggestions
I also took the freedom to add type checking, as we can't limit the
usage of `Add()` since it's a Container. The exception thrown also
advises of using the suggested `AddTrigger()` instead.
---
.../Visual/Gameplay/TestSceneAutoplay.cs | 2 +-
.../Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +-
.../Visual/Gameplay/TestSceneKeyCounter.cs | 4 +-
.../TestSceneSkinEditorMultipleSkins.cs | 2 +-
.../Gameplay/TestSceneSkinnableHUDOverlay.cs | 2 +-
osu.Game/Rulesets/UI/RulesetInputManager.cs | 10 +--
.../Screens/Play/DefaultKeyCounterDisplay.cs | 27 ++++--
osu.Game/Screens/Play/KeyCounter.cs | 6 +-
osu.Game/Screens/Play/KeyCounterDisplay.cs | 84 +++++++++++--------
osu.Game/Screens/Play/Player.cs | 7 +-
10 files changed, 86 insertions(+), 60 deletions(-)
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
index 4b6e1f089f..903cd178b7 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAutoplay.cs
@@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses.Value > 2));
seekTo(referenceBeatmap.Breaks[0].StartTime);
- AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
+ AddAssert("keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting.Value);
AddAssert("overlay displays 100% accuracy", () => Player.BreakOverlay.ChildrenOfType().Single().AccuracyDisplay.Current.Value == 1);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
index af79650d29..a586d798f5 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs
@@ -267,7 +267,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
+ hudOverlay.KeyCounter.AddTrigger(new KeyCounterKeyboardTrigger(Key.Space));
scoreProcessor.Combo.Value = 1;
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
index 9eeee800d9..5405274cd0 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddStep("Add random", () =>
{
Key key = (Key)((int)Key.A + RNG.Next(26));
- kc.Add(kc.CreateKeyCounter(new KeyCounterKeyboardTrigger(key)));
+ kc.AddTrigger(new KeyCounterKeyboardTrigger(key));
});
Key testKey = ((KeyCounterKeyboardTrigger)kc.Children.First().Trigger).Key;
@@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Gameplay
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 1);
addPressKeyStep();
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses.Value == 2);
- AddStep("Disable counting", () => testCounter.IsCounting = false);
+ AddStep("Disable counting", () => testCounter.IsCounting.Value = false);
addPressKeyStep();
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses.Value == 2);
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
index 432ff2fc7e..e4f257582d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinEditorMultipleSkins.cs
@@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
+ hudOverlay.KeyCounter.AddTrigger(new KeyCounterKeyboardTrigger(Key.Space));
scoreProcessor.Combo.Value = 1;
return new Container
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
index 24de29fa03..9848894f84 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSkinnableHUDOverlay.cs
@@ -88,7 +88,7 @@ namespace osu.Game.Tests.Visual.Gameplay
hudOverlay = new HUDOverlay(null, Array.Empty());
// Add any key just to display the key counter visually.
- hudOverlay.KeyCounter.Add(hudOverlay.KeyCounter.CreateKeyCounter(new KeyCounterKeyboardTrigger(Key.Space)));
+ hudOverlay.KeyCounter.AddTrigger(new KeyCounterKeyboardTrigger(Key.Space));
action?.Invoke(hudOverlay);
diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 6a38fa4824..32b2a19e21 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -162,11 +162,11 @@ namespace osu.Game.Rulesets.UI
KeyBindingContainer.Add(receptor);
keyCounter.SetReceptor(receptor);
- keyCounter.AddRange(KeyBindingContainer.DefaultKeyBindings
- .Select(b => b.GetAction())
- .Distinct()
- .OrderBy(action => action)
- .Select(action => keyCounter.CreateKeyCounter(new KeyCounterActionTrigger(action))));
+ keyCounter.AddTriggerRange(KeyBindingContainer.DefaultKeyBindings
+ .Select(b => b.GetAction())
+ .Distinct()
+ .OrderBy(action => action)
+ .Select(action => new KeyCounterActionTrigger(action)));
}
private partial class ActionReceptor : KeyCounterDisplay.Receptor, IKeyBindingHandler
diff --git a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
index fbf1b87395..367eb483a0 100644
--- a/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
+++ b/osu.Game/Screens/Play/DefaultKeyCounterDisplay.cs
@@ -13,7 +13,9 @@ namespace osu.Game.Screens.Play
private const int duration = 100;
private const double key_fade_time = 80;
- protected override Container