diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-0@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-0@2x.png new file mode 100644 index 0000000000..67d2e2cf04 Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-0@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-1@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-1@2x.png new file mode 100644 index 0000000000..2df10655ef Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-1@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-2@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-2@2x.png new file mode 100644 index 0000000000..eeb8ec0edf Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-2@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-3@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-3@2x.png new file mode 100644 index 0000000000..4ee73f503a Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-3@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-4@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-4@2x.png new file mode 100644 index 0000000000..eab26e36a0 Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-4@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-5@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-5@2x.png new file mode 100644 index 0000000000..8056248a4b Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-5@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-6@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-6@2x.png new file mode 100644 index 0000000000..f7ca3de273 Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-6@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-7@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-7@2x.png new file mode 100644 index 0000000000..49541c4228 Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-7@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-8@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-8@2x.png new file mode 100644 index 0000000000..343b60f475 Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-8@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-9@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-9@2x.png new file mode 100644 index 0000000000..53b687fdea Binary files /dev/null and b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/display-9@2x.png differ diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/skin.ini b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/skin.ini index 49ac2cf80d..9d16267d73 100644 --- a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/skin.ini +++ b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/skin.ini @@ -1,3 +1,4 @@ [General] Version: latest HitCircleOverlayAboveNumber: 0 +HitCirclePrefix: display \ No newline at end of file diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs index af02087d1a..30b0451a3b 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneHitCircle.cs @@ -34,6 +34,7 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("Hit Big Stream", () => SetContents(_ => testStream(2, true))); AddStep("Hit Medium Stream", () => SetContents(_ => testStream(5, true))); AddStep("Hit Small Stream", () => SetContents(_ => testStream(7, true))); + AddStep("High combo index", () => SetContents(_ => testSingle(2, true, comboIndex: 15))); } [Test] @@ -66,12 +67,12 @@ namespace osu.Game.Rulesets.Osu.Tests AddStep("Hit Big Single", () => SetContents(_ => testSingle(2, true))); } - private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null) + private Drawable testSingle(float circleSize, bool auto = false, double timeOffset = 0, Vector2? positionOffset = null, int comboIndex = 0) { var playfield = new TestOsuPlayfield(); for (double t = timeOffset; t < timeOffset + 60000; t += 2000) - playfield.Add(createSingle(circleSize, auto, t, positionOffset)); + playfield.Add(createSingle(circleSize, auto, t, positionOffset, comboIndex: comboIndex)); return playfield; } @@ -84,14 +85,14 @@ namespace osu.Game.Rulesets.Osu.Tests for (int i = 0; i <= 1000; i += 100) { - playfield.Add(createSingle(circleSize, auto, i, pos, hitOffset)); + playfield.Add(createSingle(circleSize, auto, i, pos, hitOffset, i / 100 - 1)); pos.X += 50; } return playfield; } - private TestDrawableHitCircle createSingle(float circleSize, bool auto, double timeOffset, Vector2? positionOffset, double hitOffset = 0) + private TestDrawableHitCircle createSingle(float circleSize, bool auto, double timeOffset, Vector2? positionOffset, double hitOffset = 0, int comboIndex = 0) { positionOffset ??= Vector2.Zero; @@ -99,6 +100,7 @@ namespace osu.Game.Rulesets.Osu.Tests { StartTime = Time.Current + 1000 + timeOffset, Position = OsuPlayfield.BASE_SIZE / 4 + positionOffset.Value, + IndexInCurrentCombo = comboIndex, }; circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize }); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs index 28acb4a996..5a95eac0f1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Origin = Anchor.Centre, Scale = new Vector2(SPRITE_SCALE), Y = SPINNER_TOP_OFFSET + 299, - }.With(s => s.Font = s.Font.With(fixedWidth: false)), + }, spmBackground = new Sprite { Anchor = Anchor.TopCentre, @@ -102,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Origin = Anchor.TopRight, Scale = new Vector2(SPRITE_SCALE * 0.9f), Position = new Vector2(80, 448 + spm_hide_offset), - }.With(s => s.Font = s.Font.With(fixedWidth: false)), + }, } }); } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 1de8fefaae..c01d28c8e1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -145,10 +145,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy return null; const float hitcircle_text_scale = 0.8f; - return new LegacySpriteText(LegacyFont.HitCircle, OsuHitObject.OBJECT_DIMENSIONS * 2 / hitcircle_text_scale) + return new LegacySpriteText(LegacyFont.HitCircle) { // stable applies a blanket 0.8x scale to hitcircle fonts Scale = new Vector2(hitcircle_text_scale), + MaxSizePerGlyph = OsuHitObject.OBJECT_DIMENSIONS * 2 / hitcircle_text_scale, }; case OsuSkinComponents.SpinnerBody: diff --git a/osu.Game/Skinning/LegacyAccuracyCounter.cs b/osu.Game/Skinning/LegacyAccuracyCounter.cs index 326257c25f..ed12292eb3 100644 --- a/osu.Game/Skinning/LegacyAccuracyCounter.cs +++ b/osu.Game/Skinning/LegacyAccuracyCounter.cs @@ -25,6 +25,7 @@ namespace osu.Game.Skinning { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + FixedWidth = true, }; } } diff --git a/osu.Game/Skinning/LegacyScoreCounter.cs b/osu.Game/Skinning/LegacyScoreCounter.cs index d238369be1..a86f122836 100644 --- a/osu.Game/Skinning/LegacyScoreCounter.cs +++ b/osu.Game/Skinning/LegacyScoreCounter.cs @@ -28,6 +28,7 @@ namespace osu.Game.Skinning { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, + FixedWidth = true, }; } } diff --git a/osu.Game/Skinning/LegacySpriteText.cs b/osu.Game/Skinning/LegacySpriteText.cs index 7eb92126fa..041a32e8de 100644 --- a/osu.Game/Skinning/LegacySpriteText.cs +++ b/osu.Game/Skinning/LegacySpriteText.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 System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Graphics.Sprites; @@ -12,8 +13,10 @@ namespace osu.Game.Skinning { public sealed partial class LegacySpriteText : OsuSpriteText { + public Vector2? MaxSizePerGlyph { get; init; } + public bool FixedWidth { get; init; } + private readonly LegacyFont font; - private readonly Vector2? maxSizePerGlyph; private LegacyGlyphStore glyphStore = null!; @@ -21,10 +24,18 @@ namespace osu.Game.Skinning protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x' }; - public LegacySpriteText(LegacyFont font, Vector2? maxSizePerGlyph = null) + // ReSharper disable once UnusedMember.Global + // being unused is the point here + public new FontUsage Font + { + get => base.Font; + set => throw new InvalidOperationException(@"Attempting to use this setter will not work correctly. " + + $@"Use specific init-only properties exposed by {nameof(LegacySpriteText)} instead."); + } + + public LegacySpriteText(LegacyFont font) { this.font = font; - this.maxSizePerGlyph = maxSizePerGlyph; Shadow = false; UseFullGlyphHeight = false; @@ -33,10 +44,10 @@ namespace osu.Game.Skinning [BackgroundDependencyLoader] private void load(ISkinSource skin) { - Font = new FontUsage(skin.GetFontPrefix(font), 1, fixedWidth: true); + base.Font = new FontUsage(skin.GetFontPrefix(font), 1, fixedWidth: FixedWidth); Spacing = new Vector2(-skin.GetFontOverlap(font), 0); - glyphStore = new LegacyGlyphStore(skin, maxSizePerGlyph); + glyphStore = new LegacyGlyphStore(skin, MaxSizePerGlyph); } protected override TextBuilder CreateTextBuilder(ITexturedGlyphLookupStore store) => base.CreateTextBuilder(glyphStore);