Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private void onDirectionChanged()
float hitPosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.HitPosition)?.Value ?? 0;
float scorePosition = skin.GetManiaSkinConfig<float>(LegacyManiaSkinConfigurationLookups.ScorePosition)?.Value ?? 0;

float hitPositionFromTop = 480f * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR - hitPosition;
float hitPositionFromTop = 480f * LegacySkin.POSITION_SCALE_FACTOR - hitPosition;

if (scorePosition > hitPositionFromTop / 2f)
{
Expand Down
Binary file not shown.
2 changes: 2 additions & 0 deletions osu.Game.Tests/Skins/SkinDeserialisationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ public class SkinDeserialisationTest
"Archives/modified-classic-20250827.osk",
// Covers "Argon" judgement counter
"Archives/modified-argon-20250308.osk",
// Covers legacy bar hit error meter
"Archives/modified-classic-20260806.osk",
};

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using osu.Game.Online.Spectator;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
Expand Down Expand Up @@ -101,6 +102,7 @@ public void TestLayout(
(typeof(IGameplayClock), gameplayClock = new GameplayClockContainer(new TrackVirtual(60000), false, false)),
(typeof(SpectatorClient), spectatorClient),
(typeof(IGameplayLeaderboardProvider), new TestGameplayLeaderboardProvider()),
(typeof(DrawableRuleset), ruleset.CreateDrawableRulesetWith(CreateWorkingBeatmap(ruleset.RulesetInfo).GetPlayableBeatmap(ruleset.RulesetInfo)))
];

if (drawableRuleset is IDrawableScrollingRuleset scrolling)
Expand Down
23 changes: 23 additions & 0 deletions osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,29 @@ private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
Rotation = 270,
Margin = new MarginPadding { Left = 50 }
});

Add(new LegacyBarHitErrorMeter
{
Anchor = Anchor.CentreRight,
Origin = Anchor.BottomCentre,
Rotation = 90,
X = -100,
});

Add(new LegacyBarHitErrorMeter
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.BottomCentre,
Rotation = 90,
X = 100,
});

Add(new LegacyBarHitErrorMeter
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Y = -100
});
}

private void newJudgement(double offset = 0, HitResult result = HitResult.Perfect)
Expand Down
152 changes: 152 additions & 0 deletions osu.Game/Screens/Play/HUD/HitErrorMeters/LegacyBarHitErrorMeter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using osuTK;

namespace osu.Game.Screens.Play.HUD.HitErrorMeters
{
/// <seealso href="https://github.com/peppy/osu-stable-reference/blob/baa8705f782c0de2b10a7387d78014c61c8b17fb/osu!/GameModes/Play/Components/ScoreMeterError.cs"/>
public partial class LegacyBarHitErrorMeter : HitErrorMeter
{
private const float bar_height = 3;

private (HitResult result, double length)[] hitWindows = null!;
private DrawablePool<JudgementLine> judgementLinePool = null!;
private Container judgementContainer = null!;
private Triangle arrow = null!;

private double maxHitWindow = 1;
private float floatingError;

[BackgroundDependencyLoader]
private void load()
{
Container colourBarContainer;

hitWindows = HitWindows.GetAllAvailableWindows().Where(w => w.result.IsHit()).ToArray();

AutoSizeAxes = Axes.X;
Height = (bar_height * 4) * LegacySkin.POSITION_SCALE_FACTOR;
Origin = Anchor.Centre;
InternalChildren = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Colour4.Black,
Alpha = 0.6f,
},
colourBarContainer = new Container
{
AutoSizeAxes = Axes.X,
Height = bar_height * LegacySkin.POSITION_SCALE_FACTOR,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(1.5f, bar_height * 4) * LegacySkin.POSITION_SCALE_FACTOR,
},
judgementLinePool = new DrawablePool<JudgementLine>(50),
judgementContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
arrow = new Triangle
{
Size = new Vector2(17, 8) * 0.6f,
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
RelativePositionAxes = Axes.X,
Scale = new Vector2(1, -1),
}
};

foreach (var hitWindow in hitWindows)
{
maxHitWindow = Math.Max(maxHitWindow, hitWindow.length);

colourBarContainer.Add(new Box
{
Size = new Vector2((float)hitWindow.length, bar_height) * LegacySkin.POSITION_SCALE_FACTOR,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Colour = GetColourForHitResult(hitWindow.result),
});
}
}

protected override void OnNewJudgement(JudgementResult judgement)
{
if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0)
return;

if (!judgement.Type.IsScorable() || judgement.Type.IsBonus())
return;

float relativePosition = getRelativeJudgementPosition(judgement.TimeOffset);

judgementLinePool.Get(drawableJudgement =>
{
drawableJudgement.X = relativePosition;
drawableJudgement.Colour = GetColourForHitResult(judgement.Type);

judgementContainer.Add(drawableJudgement);
});

floatingError = floatingError * 0.8f + relativePosition * 0.2f;
arrow.MoveToX(floatingError, 800, Easing.Out);
}

private float getRelativeJudgementPosition(double value) => Math.Clamp((float)(value / maxHitWindow) / 2, -0.5f, 0.5f);

public override void Clear()
{
foreach (var j in judgementContainer)
{
j.ClearTransforms();
j.Expire();
}
}

internal partial class JudgementLine : PoolableDrawable
{
[BackgroundDependencyLoader]
private void load()
{
RelativeSizeAxes = Axes.Y;
Width = 3;
RelativePositionAxes = Axes.X;
Blending = BlendingParameters.Additive;
Anchor = Anchor.Centre;
Origin = Anchor.Centre;

InternalChild = new Box { RelativeSizeAxes = Axes.Both };
}

protected override void PrepareForUse()
{
base.PrepareForUse();

this.FadeTo(0.4f)
.Then()
.FadeOut(10000)
.Expire();
}
}
}
}
15 changes: 5 additions & 10 deletions osu.Game/Skinning/LegacyManiaSkinConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,12 @@ namespace osu.Game.Skinning
{
public class LegacyManiaSkinConfiguration : IHasCustomColours
{
/// <summary>
/// Conversion factor from converting legacy positioning values (based in x480 dimensions) to x768.
/// </summary>
public const float POSITION_SCALE_FACTOR = 1.6f;

/// <summary>
/// Size of a legacy column in the default skin, used for determining relative scale factors.
/// </summary>
public const float DEFAULT_COLUMN_SIZE = 30 * POSITION_SCALE_FACTOR;
public const float DEFAULT_COLUMN_SIZE = 30 * LegacySkin.POSITION_SCALE_FACTOR;

public const float DEFAULT_HIT_POSITION = (480 - 402) * POSITION_SCALE_FACTOR;
public const float DEFAULT_HIT_POSITION = (480 - 402) * LegacySkin.POSITION_SCALE_FACTOR;

public readonly int Keys;

Expand All @@ -38,9 +33,9 @@ public class LegacyManiaSkinConfiguration : IHasCustomColours
public readonly float[] HoldNoteLightWidth;

public float HitPosition = DEFAULT_HIT_POSITION;
public float LightPosition = (480 - 413) * POSITION_SCALE_FACTOR;
public float ComboPosition = 111 * POSITION_SCALE_FACTOR;
public float ScorePosition = 300 * POSITION_SCALE_FACTOR;
public float LightPosition = (480 - 413) * LegacySkin.POSITION_SCALE_FACTOR;
public float ComboPosition = 111 * LegacySkin.POSITION_SCALE_FACTOR;
public float ScorePosition = 300 * LegacySkin.POSITION_SCALE_FACTOR;
public float BarLineHeight = 1.2f;
public bool ShowJudgementLine = true;
public bool KeysUnderNotes;
Expand Down
12 changes: 6 additions & 6 deletions osu.Game/Skinning/LegacyManiaSkinDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,19 @@ private void flushPendingLines()
break;

case "HitPosition":
currentConfig.HitPosition = (480 - Math.Clamp(float.Parse(pair.Value, CultureInfo.InvariantCulture), 240, 480)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
currentConfig.HitPosition = (480 - Math.Clamp(float.Parse(pair.Value, CultureInfo.InvariantCulture), 240, 480)) * LegacySkin.POSITION_SCALE_FACTOR;
break;

case "LightPosition":
currentConfig.LightPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
currentConfig.LightPosition = (480 - float.Parse(pair.Value, CultureInfo.InvariantCulture)) * LegacySkin.POSITION_SCALE_FACTOR;
break;

case "ComboPosition":
currentConfig.ComboPosition = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
currentConfig.ComboPosition = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacySkin.POSITION_SCALE_FACTOR;
break;

case "ScorePosition":
currentConfig.ScorePosition = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
currentConfig.ScorePosition = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacySkin.POSITION_SCALE_FACTOR;
break;

case "JudgementLine":
Expand All @@ -128,7 +128,7 @@ private void flushPendingLines()
break;

case "WidthForNoteHeightScale":
currentConfig.WidthForNoteHeightScale = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
currentConfig.WidthForNoteHeightScale = float.Parse(pair.Value, CultureInfo.InvariantCulture) * LegacySkin.POSITION_SCALE_FACTOR;
break;

case "LightFramePerSecond":
Expand Down Expand Up @@ -209,7 +209,7 @@ private void parseArrayValue(string value, float[] output, bool applyScaleFactor
parsedValue = 0;

if (applyScaleFactor)
parsedValue *= LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
parsedValue *= LegacySkin.POSITION_SCALE_FACTOR;

output[i] = parsedValue;
}
Expand Down
10 changes: 7 additions & 3 deletions osu.Game/Skinning/LegacySkin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ namespace osu.Game.Skinning
{
public class LegacySkin : Skin
{
/// <summary>
/// Conversion factor from converting legacy positioning values (based in x480 dimensions) to x768.
/// </summary>
public const float POSITION_SCALE_FACTOR = 1.6f;

protected virtual bool AllowManiaConfigLookups => true;

/// <summary>
Expand Down Expand Up @@ -448,8 +453,7 @@ protected override void ParseConfigurationStream(Stream stream)
if (hitError != null)
{
hitError.Anchor = Anchor.BottomCentre;
hitError.Origin = Anchor.CentreLeft;
hitError.Rotation = -90;
hitError.Origin = Anchor.BottomCentre;
}

foreach (var d in container.OfType<ISerialisableDrawable>())
Expand All @@ -461,7 +465,7 @@ protected override void ParseConfigurationStream(Stream stream)
new LegacyScoreCounter(),
new LegacyAccuracyCounter(),
new LegacySongProgress(),
new BarHitErrorMeter(),
new LegacyBarHitErrorMeter(),

// to match stable, health bars are in front of everything else
// for the sake of hacky full screen area health bars
Expand Down
6 changes: 3 additions & 3 deletions osu.Game/Skinning/LegacySkinEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ public void Encode(TextWriter textWriter)
writeValue(textWriter, @"JudgementLine", maniaConfig.ShowJudgementLine ? @"1" : @"0");
writeValue(textWriter, @"BarlineHeight", maniaConfig.BarLineHeight.ToString(CultureInfo.InvariantCulture), defaultValue: @"1.2");

float hitPosition = 480 - (maniaConfig.HitPosition / LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR);
float hitPosition = 480 - (maniaConfig.HitPosition / LegacySkin.POSITION_SCALE_FACTOR);
writeValue(textWriter, @"HitPosition", hitPosition.ToString(CultureInfo.InvariantCulture), defaultValue: @"402");

float lightPosition = 480 - (maniaConfig.LightPosition / LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR);
float lightPosition = 480 - (maniaConfig.LightPosition / LegacySkin.POSITION_SCALE_FACTOR);
writeValue(textWriter, @"LightPosition", lightPosition.ToString(CultureInfo.InvariantCulture), defaultValue: @"413");

writeValue(textWriter, @"ComboPosition", undoPositionScaleFactor(maniaConfig.ComboPosition).ToString(CultureInfo.InvariantCulture), defaultValue: @"111");
Expand Down Expand Up @@ -189,7 +189,7 @@ private void writeGenericColour(TextWriter textWriter, Dictionary<string, Color4
: FormattableString.Invariant($"{(int)(colour.Value.R * 255)},{(int)(colour.Value.G * 255)},{(int)(colour.Value.B * 255)}");
}

private float undoPositionScaleFactor(float f) => f / LegacyManiaSkinConfiguration.POSITION_SCALE_FACTOR;
private float undoPositionScaleFactor(float f) => f / LegacySkin.POSITION_SCALE_FACTOR;

private string enumerableToString<T>(IEnumerable<T?> ts)
where T : IFormattable
Expand Down
Loading