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

Merge branch 'master' into fix-timeline-depth-ordering

This commit is contained in:
Dan Balasescu 2021-03-29 20:47:47 +09:00 committed by GitHub
commit 1bb9f018a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 214 additions and 124 deletions

View File

@ -5,7 +5,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK.Graphics; using osuTK.Graphics;
using static osu.Game.Skinning.LegacySkinConfiguration;
namespace osu.Game.Rulesets.Catch.Skinning.Legacy namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{ {
@ -14,7 +13,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
/// <summary> /// <summary>
/// For simplicity, let's use legacy combo font texture existence as a way to identify legacy skins from default. /// For simplicity, let's use legacy combo font texture existence as a way to identify legacy skins from default.
/// </summary> /// </summary>
private bool providesComboCounter => this.HasFont(GetConfig<LegacySetting, string>(LegacySetting.ComboPrefix)?.Value ?? "score"); private bool providesComboCounter => this.HasFont(LegacyFont.Combo);
public CatchLegacySkinTransformer(ISkinSource source) public CatchLegacySkinTransformer(ISkinSource source)
: base(source) : base(source)
@ -69,7 +68,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
this.GetAnimation("fruit-ryuuta", true, true, true); this.GetAnimation("fruit-ryuuta", true, true, true);
case CatchSkinComponents.CatchComboCounter: case CatchSkinComponents.CatchComboCounter:
if (providesComboCounter) if (providesComboCounter)
return new LegacyCatchComboCounter(Source); return new LegacyCatchComboCounter(Source);

View File

@ -7,7 +7,6 @@ using osu.Game.Rulesets.Catch.UI;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using static osu.Game.Skinning.LegacySkinConfiguration;
namespace osu.Game.Rulesets.Catch.Skinning.Legacy namespace osu.Game.Rulesets.Catch.Skinning.Legacy
{ {
@ -22,9 +21,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
public LegacyCatchComboCounter(ISkin skin) public LegacyCatchComboCounter(ISkin skin)
{ {
var fontName = skin.GetConfig<LegacySetting, string>(LegacySetting.ComboPrefix)?.Value ?? "score";
var fontOverlap = skin.GetConfig<LegacySetting, float>(LegacySetting.ComboOverlap)?.Value ?? -2f;
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Alpha = 0f; Alpha = 0f;
@ -34,7 +30,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
explosion = new LegacyRollingCounter(skin, fontName, fontOverlap) explosion = new LegacyRollingCounter(skin, LegacyFont.Combo)
{ {
Alpha = 0.65f, Alpha = 0.65f,
Blending = BlendingParameters.Additive, Blending = BlendingParameters.Additive,
@ -42,7 +38,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy
Origin = Anchor.Centre, Origin = Anchor.Centre,
Scale = new Vector2(1.5f), Scale = new Vector2(1.5f),
}, },
counter = new LegacyRollingCounter(skin, fontName, fontOverlap) counter = new LegacyRollingCounter(skin, LegacyFont.Combo)
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -119,5 +119,8 @@ namespace osu.Game.Rulesets.Mania.Edit
beatSnapGrid.SelectionTimeRange = null; beatSnapGrid.SelectionTimeRange = null;
} }
} }
public override string ConvertSelectionToString()
=> string.Join(',', EditorBeatmap.SelectedHitObjects.Cast<ManiaHitObject>().OrderBy(h => h.StartTime).Select(h => $"{h.StartTime}|{h.Column}"));
} }
} }

View File

@ -82,6 +82,9 @@ namespace osu.Game.Rulesets.Osu.Edit
protected override ComposeBlueprintContainer CreateBlueprintContainer() protected override ComposeBlueprintContainer CreateBlueprintContainer()
=> new OsuBlueprintContainer(this); => new OsuBlueprintContainer(this);
public override string ConvertSelectionToString()
=> string.Join(',', selectedHitObjects.Cast<OsuHitObject>().OrderBy(h => h.StartTime).Select(h => (h.IndexInCurrentCombo + 1).ToString()));
private DistanceSnapGrid distanceSnapGrid; private DistanceSnapGrid distanceSnapGrid;
private Container distanceSnapGridContainer; private Container distanceSnapGridContainer;

View File

@ -48,9 +48,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
DrawableSpinner = (DrawableSpinner)drawableHitObject; DrawableSpinner = (DrawableSpinner)drawableHitObject;
Container overlayContainer; AddInternal(new Container
AddInternal(overlayContainer = new Container
{ {
Depth = float.MinValue, Depth = float.MinValue,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -73,21 +71,16 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
Scale = new Vector2(SPRITE_SCALE), Scale = new Vector2(SPRITE_SCALE),
Y = SPINNER_TOP_OFFSET + 115, Y = SPINNER_TOP_OFFSET + 115,
}, },
bonusCounter = new LegacySpriteText(source, LegacyFont.Score)
{
Alpha = 0f,
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Scale = new Vector2(SPRITE_SCALE),
Y = SPINNER_TOP_OFFSET + 299,
}.With(s => s.Font = s.Font.With(fixedWidth: false)),
} }
}); });
bonusCounter = (source.GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreText)) as LegacySpriteText)?.With(c =>
{
c.Alpha = 0f;
c.Anchor = Anchor.TopCentre;
c.Origin = Anchor.Centre;
c.Font = c.Font.With(fixedWidth: false);
c.Scale = new Vector2(SPRITE_SCALE);
c.Y = SPINNER_TOP_OFFSET + 299;
});
if (bonusCounter != null)
overlayContainer.Add(bonusCounter);
} }
private IBindable<double> gainedBonus; private IBindable<double> gainedBonus;
@ -98,16 +91,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
{ {
base.LoadComplete(); base.LoadComplete();
if (bonusCounter != null) gainedBonus = DrawableSpinner.GainedBonus.GetBoundCopy();
gainedBonus.BindValueChanged(bonus =>
{ {
gainedBonus = DrawableSpinner.GainedBonus.GetBoundCopy(); bonusCounter.Text = bonus.NewValue.ToString(NumberFormatInfo.InvariantInfo);
gainedBonus.BindValueChanged(bonus => bonusCounter.FadeOutFromOne(800, Easing.Out);
{ bonusCounter.ScaleTo(SPRITE_SCALE * 2f).Then().ScaleTo(SPRITE_SCALE * 1.28f, 800, Easing.Out);
bonusCounter.Text = bonus.NewValue.ToString(NumberFormatInfo.InvariantInfo); });
bonusCounter.FadeOutFromOne(800, Easing.Out);
bonusCounter.ScaleTo(SPRITE_SCALE * 2f).Then().ScaleTo(SPRITE_SCALE * 1.28f, 800, Easing.Out);
});
}
completed.BindValueChanged(onCompletedChanged, true); completed.BindValueChanged(onCompletedChanged, true);

View File

@ -97,17 +97,14 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
return null; return null;
case OsuSkinComponents.HitCircleText: case OsuSkinComponents.HitCircleText:
var font = GetConfig<OsuSkinConfiguration, string>(OsuSkinConfiguration.HitCirclePrefix)?.Value ?? "default"; if (!this.HasFont(LegacyFont.HitCircle))
var overlap = GetConfig<OsuSkinConfiguration, float>(OsuSkinConfiguration.HitCircleOverlap)?.Value ?? -2; return null;
return !this.HasFont(font) return new LegacySpriteText(Source, LegacyFont.HitCircle)
? null {
: new LegacySpriteText(Source, font) // stable applies a blanket 0.8x scale to hitcircle fonts
{ Scale = new Vector2(0.8f),
// stable applies a blanket 0.8x scale to hitcircle fonts };
Scale = new Vector2(0.8f),
Spacing = new Vector2(-overlap, 0)
};
case OsuSkinComponents.SpinnerBody: case OsuSkinComponents.SpinnerBody:
bool hasBackground = Source.GetTexture("spinner-background") != null; bool hasBackground = Source.GetTexture("spinner-background") != null;

View File

@ -5,8 +5,6 @@ namespace osu.Game.Rulesets.Osu.Skinning
{ {
public enum OsuSkinConfiguration public enum OsuSkinConfiguration
{ {
HitCirclePrefix,
HitCircleOverlap,
SliderBorderSize, SliderBorderSize,
SliderPathRadius, SliderPathRadius,
AllowSliderBallTint, AllowSliderBallTint,

View File

@ -0,0 +1,26 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Globalization;
using NUnit.Framework;
using osu.Game.Utils;
namespace osu.Game.Tests.NonVisual
{
[TestFixture]
public class FormatUtilsTest
{
[TestCase(0, "0.00%")]
[TestCase(0.01, "1.00%")]
[TestCase(0.9899, "98.99%")]
[TestCase(0.989999, "98.99%")]
[TestCase(0.99, "99.00%")]
[TestCase(0.9999, "99.99%")]
[TestCase(0.999999, "99.99%")]
[TestCase(1, "100.00%")]
public void TestAccuracyFormatting(double input, string expectedOutput)
{
Assert.AreEqual(expectedOutput, input.FormatAccuracy(CultureInfo.InvariantCulture));
}
}
}

View File

@ -275,7 +275,8 @@ namespace osu.Game.Overlays.Chat
{ {
if (!UserScrolling) if (!UserScrolling)
{ {
ScrollToEnd(); if (Current < ScrollableExtent)
ScrollToEnd();
lastExtent = ScrollableExtent; lastExtent = ScrollableExtent;
} }
}); });

View File

@ -438,6 +438,8 @@ namespace osu.Game.Rulesets.Edit
/// </summary> /// </summary>
public abstract bool CursorInPlacementArea { get; } public abstract bool CursorInPlacementArea { get; }
public virtual string ConvertSelectionToString() => string.Empty;
#region IPositionSnapProvider #region IPositionSnapProvider
public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition); public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);

View File

@ -337,7 +337,7 @@ namespace osu.Game.Rulesets.Scoring
score.TotalScore = (long)Math.Round(GetStandardisedScore()); score.TotalScore = (long)Math.Round(GetStandardisedScore());
score.Combo = Combo.Value; score.Combo = Combo.Value;
score.MaxCombo = HighestCombo.Value; score.MaxCombo = HighestCombo.Value;
score.Accuracy = Math.Round(Accuracy.Value, 4); score.Accuracy = Accuracy.Value;
score.Rank = Rank.Value; score.Rank = Rank.Value;
score.Date = DateTimeOffset.Now; score.Date = DateTimeOffset.Now;

View File

@ -30,7 +30,7 @@ namespace osu.Game.Scoring
public long TotalScore { get; set; } public long TotalScore { get; set; }
[JsonProperty("accuracy")] [JsonProperty("accuracy")]
[Column(TypeName = "DECIMAL(1,4)")] [Column(TypeName = "DECIMAL(1,4)")] // TODO: This data type is wrong (should contain more precision). But at the same time, we probably don't need to be storing this in the database.
public double Accuracy { get; set; } public double Accuracy { get; set; }
[JsonIgnore] [JsonIgnore]

View File

@ -2,11 +2,16 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Framework.Platform;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Compose.Components.Timeline; using osu.Game.Screens.Edit.Compose.Components.Timeline;
@ -14,11 +19,17 @@ using osu.Game.Skinning;
namespace osu.Game.Screens.Edit.Compose namespace osu.Game.Screens.Edit.Compose
{ {
public class ComposeScreen : EditorScreenWithTimeline public class ComposeScreen : EditorScreenWithTimeline, IKeyBindingHandler<PlatformAction>
{ {
[Resolved] [Resolved]
private IBindable<WorkingBeatmap> beatmap { get; set; } private IBindable<WorkingBeatmap> beatmap { get; set; }
[Resolved]
private GameHost host { get; set; }
[Resolved]
private EditorClock clock { get; set; }
private HitObjectComposer composer; private HitObjectComposer composer;
public ComposeScreen() public ComposeScreen()
@ -72,5 +83,34 @@ namespace osu.Game.Screens.Edit.Compose
// this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources. // this is intentionally done in two stages to ensure things are in a loaded state before exposing the ruleset to skin sources.
return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(content)); return beatmapSkinProvider.WithChild(rulesetSkinProvider.WithChild(content));
} }
#region Input Handling
public bool OnPressed(PlatformAction action)
{
if (action.ActionType == PlatformActionType.Copy)
host.GetClipboard().SetText(formatSelectionAsString());
return false;
}
public void OnReleased(PlatformAction action)
{
}
private string formatSelectionAsString()
{
if (composer == null)
return string.Empty;
double displayTime = EditorBeatmap.SelectedHitObjects.OrderBy(h => h.StartTime).FirstOrDefault()?.StartTime ?? clock.CurrentTime;
string selectionAsString = composer.ConvertSelectionToString();
return !string.IsNullOrEmpty(selectionAsString)
? $"{displayTime.ToEditorFormattedString()} ({selectionAsString}) - "
: $"{displayTime.ToEditorFormattedString()} - ";
}
#endregion
} }
} }

View File

@ -16,7 +16,6 @@ using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -103,7 +102,7 @@ namespace osu.Game.Screens.Edit
private MusicController music { get; set; } private MusicController music { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, GameHost host, OsuConfigManager config) private void load(OsuColour colours, OsuConfigManager config)
{ {
var loadableBeatmap = Beatmap.Value; var loadableBeatmap = Beatmap.Value;

View File

@ -2,7 +2,6 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Diagnostics;
using System.Linq; using System.Linq;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -170,7 +169,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge
private void joinRequested(Room room) private void joinRequested(Room room)
{ {
Debug.Assert(joiningRoomOperation == null); if (joiningRoomOperation != null)
return;
joiningRoomOperation = ongoingOperationTracker?.BeginOperation(); joiningRoomOperation = ongoingOperationTracker?.BeginOperation();
RoomManager?.JoinRoom(room, r => RoomManager?.JoinRoom(room, r =>

View File

@ -6,7 +6,6 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Sprites;
using osu.Game.Skinning; using osu.Game.Skinning;
using osuTK; using osuTK;
@ -84,16 +83,16 @@ namespace osu.Game.Screens.Play.HUD
{ {
InternalChildren = new[] InternalChildren = new[]
{ {
popOutCount = createSpriteText().With(s => popOutCount = new LegacySpriteText(skin, LegacyFont.Combo)
{ {
s.Alpha = 0; Alpha = 0,
s.Margin = new MarginPadding(0.05f); Margin = new MarginPadding(0.05f),
s.Blending = BlendingParameters.Additive; Blending = BlendingParameters.Additive,
}), },
displayedCountSpriteText = createSpriteText().With(s => displayedCountSpriteText = new LegacySpriteText(skin, LegacyFont.Combo)
{ {
s.Alpha = 0; Alpha = 0,
}) },
}; };
Current.ValueChanged += combo => updateCount(combo.NewValue == 0); Current.ValueChanged += combo => updateCount(combo.NewValue == 0);
@ -247,7 +246,5 @@ namespace osu.Game.Screens.Play.HUD
double difference = currentValue > newValue ? currentValue - newValue : newValue - currentValue; double difference = currentValue > newValue ? currentValue - newValue : newValue - currentValue;
return difference * rolling_duration; return difference * rolling_duration;
} }
private OsuSpriteText createSpriteText() => (OsuSpriteText)skin.GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ComboText));
} }
} }

View File

@ -9,7 +9,5 @@ namespace osu.Game.Skinning
ScoreCounter, ScoreCounter,
AccuracyCounter, AccuracyCounter,
HealthDisplay, HealthDisplay,
ScoreText,
ComboText,
} }
} }

View File

@ -29,9 +29,11 @@ namespace osu.Game.Skinning
[Resolved(canBeNull: true)] [Resolved(canBeNull: true)]
private HUDOverlay hud { get; set; } private HUDOverlay hud { get; set; }
protected sealed override OsuSpriteText CreateSpriteText() protected sealed override OsuSpriteText CreateSpriteText() => new LegacySpriteText(skin, LegacyFont.Score)
=> (OsuSpriteText)skin?.GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreText)) {
?.With(s => s.Anchor = s.Origin = Anchor.TopRight); Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
};
protected override void Update() protected override void Update()
{ {

View File

@ -0,0 +1,15 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
namespace osu.Game.Skinning
{
/// <summary>
/// The type of legacy font to use for <see cref="LegacySpriteText"/>s.
/// </summary>
public enum LegacyFont
{
Score,
Combo,
HitCircle,
}
}

View File

@ -4,7 +4,6 @@
using System; using System;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osuTK;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
@ -14,9 +13,7 @@ namespace osu.Game.Skinning
public class LegacyRollingCounter : RollingCounter<int> public class LegacyRollingCounter : RollingCounter<int>
{ {
private readonly ISkin skin; private readonly ISkin skin;
private readonly LegacyFont font;
private readonly string fontName;
private readonly float fontOverlap;
protected override bool IsRollingProportional => true; protected override bool IsRollingProportional => true;
@ -24,17 +21,11 @@ namespace osu.Game.Skinning
/// Creates a new <see cref="LegacyRollingCounter"/>. /// Creates a new <see cref="LegacyRollingCounter"/>.
/// </summary> /// </summary>
/// <param name="skin">The <see cref="ISkin"/> from which to get counter number sprites.</param> /// <param name="skin">The <see cref="ISkin"/> from which to get counter number sprites.</param>
/// <param name="fontName">The name of the legacy font to use.</param> /// <param name="font">The legacy font to use for the counter.</param>
/// <param name="fontOverlap"> public LegacyRollingCounter(ISkin skin, LegacyFont font)
/// The numeric overlap of number sprites to use.
/// A positive number will bring the number sprites closer together, while a negative number
/// will split them apart more.
/// </param>
public LegacyRollingCounter(ISkin skin, string fontName, float fontOverlap)
{ {
this.skin = skin; this.skin = skin;
this.fontName = fontName; this.font = font;
this.fontOverlap = fontOverlap;
} }
protected override double GetProportionalDuration(int currentValue, int newValue) protected override double GetProportionalDuration(int currentValue, int newValue)
@ -42,10 +33,6 @@ namespace osu.Game.Skinning
return Math.Abs(newValue - currentValue) * 75.0; return Math.Abs(newValue - currentValue) * 75.0;
} }
protected sealed override OsuSpriteText CreateSpriteText() => protected sealed override OsuSpriteText CreateSpriteText() => new LegacySpriteText(skin, font);
new LegacySpriteText(skin, fontName)
{
Spacing = new Vector2(-fontOverlap, 0f)
};
} }
} }

View File

@ -33,8 +33,10 @@ namespace osu.Game.Skinning
Margin = new MarginPadding(10); Margin = new MarginPadding(10);
} }
protected sealed override OsuSpriteText CreateSpriteText() protected sealed override OsuSpriteText CreateSpriteText() => new LegacySpriteText(skin, LegacyFont.Score)
=> (OsuSpriteText)skin.GetDrawableComponent(new HUDSkinComponent(HUDSkinComponents.ScoreText)) {
.With(s => s.Anchor = s.Origin = Anchor.TopRight); Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
};
} }
} }

View File

@ -18,7 +18,6 @@ using osu.Game.Beatmaps.Formats;
using osu.Game.IO; using osu.Game.IO;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.HUD;
using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
namespace osu.Game.Skinning namespace osu.Game.Skinning
@ -320,19 +319,13 @@ namespace osu.Game.Skinning
return null; return null;
} }
private string scorePrefix => GetConfig<LegacySkinConfiguration.LegacySetting, string>(LegacySkinConfiguration.LegacySetting.ScorePrefix)?.Value ?? "score";
private string comboPrefix => GetConfig<LegacySkinConfiguration.LegacySetting, string>(LegacySkinConfiguration.LegacySetting.ComboPrefix)?.Value ?? "score";
private bool hasScoreFont => this.HasFont(scorePrefix);
public override Drawable GetDrawableComponent(ISkinComponent component) public override Drawable GetDrawableComponent(ISkinComponent component)
{ {
switch (component) switch (component)
{ {
case HUDSkinComponent hudComponent: case HUDSkinComponent hudComponent:
{ {
if (!hasScoreFont) if (!this.HasFont(LegacyFont.Score))
return null; return null;
switch (hudComponent.Component) switch (hudComponent.Component)
@ -348,18 +341,6 @@ namespace osu.Game.Skinning
case HUDSkinComponents.HealthDisplay: case HUDSkinComponents.HealthDisplay:
return new LegacyHealthDisplay(this); return new LegacyHealthDisplay(this);
case HUDSkinComponents.ComboText:
return new LegacySpriteText(this, comboPrefix)
{
Spacing = new Vector2(-(GetConfig<LegacySkinConfiguration.LegacySetting, int>(LegacySkinConfiguration.LegacySetting.ComboOverlap)?.Value ?? -2), 0)
};
case HUDSkinComponents.ScoreText:
return new LegacySpriteText(this, scorePrefix)
{
Spacing = new Vector2(-(GetConfig<LegacySkinConfiguration.LegacySetting, int>(LegacySkinConfiguration.LegacySetting.ScoreOverlap)?.Value ?? -2), 0)
};
} }
return null; return null;

View File

@ -19,6 +19,8 @@ namespace osu.Game.Skinning
ComboOverlap, ComboOverlap,
ScorePrefix, ScorePrefix,
ScoreOverlap, ScoreOverlap,
HitCirclePrefix,
HitCircleOverlap,
AnimationFramerate, AnimationFramerate,
LayeredHitSounds LayeredHitSounds
} }

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -63,8 +64,51 @@ namespace osu.Game.Skinning
} }
} }
public static bool HasFont(this ISkin source, string fontPrefix) public static bool HasFont(this ISkin source, LegacyFont font)
=> source.GetTexture($"{fontPrefix}-0") != null; {
return source.GetTexture($"{source.GetFontPrefix(font)}-0") != null;
}
public static string GetFontPrefix(this ISkin source, LegacyFont font)
{
switch (font)
{
case LegacyFont.Score:
return source.GetConfig<LegacySetting, string>(LegacySetting.ScorePrefix)?.Value ?? "score";
case LegacyFont.Combo:
return source.GetConfig<LegacySetting, string>(LegacySetting.ComboPrefix)?.Value ?? "score";
case LegacyFont.HitCircle:
return source.GetConfig<LegacySetting, string>(LegacySetting.HitCirclePrefix)?.Value ?? "default";
default:
throw new ArgumentOutOfRangeException(nameof(font));
}
}
/// <summary>
/// Returns the numeric overlap of number sprites to use.
/// A positive number will bring the number sprites closer together, while a negative number
/// will split them apart more.
/// </summary>
public static float GetFontOverlap(this ISkin source, LegacyFont font)
{
switch (font)
{
case LegacyFont.Score:
return source.GetConfig<LegacySetting, float>(LegacySetting.ScoreOverlap)?.Value ?? 0f;
case LegacyFont.Combo:
return source.GetConfig<LegacySetting, float>(LegacySetting.ComboOverlap)?.Value ?? 0f;
case LegacyFont.HitCircle:
return source.GetConfig<LegacySetting, float>(LegacySetting.HitCircleOverlap)?.Value ?? -2f;
default:
throw new ArgumentOutOfRangeException(nameof(font));
}
}
public class SkinnableTextureAnimation : TextureAnimation public class SkinnableTextureAnimation : TextureAnimation
{ {

View File

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Text; using osu.Framework.Text;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK;
namespace osu.Game.Skinning namespace osu.Game.Skinning
{ {
@ -16,12 +17,14 @@ namespace osu.Game.Skinning
protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x' }; protected override char[] FixedWidthExcludeCharacters => new[] { ',', '.', '%', 'x' };
public LegacySpriteText(ISkin skin, string font = "score") public LegacySpriteText(ISkin skin, LegacyFont font)
{ {
Shadow = false; Shadow = false;
UseFullGlyphHeight = false; UseFullGlyphHeight = false;
Font = new FontUsage(font, 1, fixedWidth: true); Font = new FontUsage(skin.GetFontPrefix(font), 1, fixedWidth: true);
Spacing = new Vector2(-skin.GetFontOverlap(font), 0);
glyphStore = new LegacyGlyphStore(skin); glyphStore = new LegacyGlyphStore(skin);
} }

View File

@ -42,7 +42,7 @@ namespace osu.Game.Users
public long RankedScore; public long RankedScore;
[JsonProperty(@"hit_accuracy")] [JsonProperty(@"hit_accuracy")]
public decimal Accuracy; public double Accuracy;
[JsonIgnore] [JsonIgnore]
public string DisplayAccuracy => Accuracy.FormatAccuracy(); public string DisplayAccuracy => Accuracy.FormatAccuracy();

View File

@ -1,6 +1,8 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Globalization;
using Humanizer; using Humanizer;
namespace osu.Game.Utils namespace osu.Game.Utils
@ -10,16 +12,19 @@ namespace osu.Game.Utils
/// <summary> /// <summary>
/// Turns the provided accuracy into a percentage with 2 decimal places. /// Turns the provided accuracy into a percentage with 2 decimal places.
/// </summary> /// </summary>
/// <param name="accuracy">The accuracy to be formatted</param> /// <param name="accuracy">The accuracy to be formatted.</param>
/// <param name="formatProvider">An optional format provider.</param>
/// <returns>formatted accuracy in percentage</returns> /// <returns>formatted accuracy in percentage</returns>
public static string FormatAccuracy(this double accuracy) => $"{accuracy:0.00%}"; public static string FormatAccuracy(this double accuracy, IFormatProvider formatProvider = null)
{
// for the sake of display purposes, we don't want to show a user a "rounded up" percentage to the next whole number.
// ie. a score which gets 89.99999% shouldn't ever show as 90%.
// the reasoning for this is that cutoffs for grade increases are at whole numbers and displaying the required
// percentile with a non-matching grade is confusing.
accuracy = Math.Floor(accuracy * 10000) / 10000;
/// <summary> return accuracy.ToString("0.00%", formatProvider ?? CultureInfo.CurrentCulture);
/// Turns the provided accuracy into a percentage with 2 decimal places. }
/// </summary>
/// <param name="accuracy">The accuracy to be formatted</param>
/// <returns>formatted accuracy in percentage</returns>
public static string FormatAccuracy(this decimal accuracy) => $"{accuracy:0.00}%";
/// <summary> /// <summary>
/// Formats the supplied rank/leaderboard position in a consistent, simplified way. /// Formats the supplied rank/leaderboard position in a consistent, simplified way.