Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limit number of allowed beatmap combo colours to 8 #32110

Merged
merged 5 commits into from
Feb 27, 2025
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
29 changes: 29 additions & 0 deletions osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,35 @@ public void TestDecodeBeatmapColours()
}
}

[Test]
public void TestComboColourCountIsLimitedToEight()
{
var decoder = new LegacySkinDecoder();

using (var resStream = TestResources.OpenResource("too-many-combo-colours.osu"))
using (var stream = new LineBufferedReader(resStream))
{
var comboColors = decoder.Decode(stream).ComboColours;

Debug.Assert(comboColors != null);

Color4[] expectedColors =
{
new Color4(142, 199, 255, 255),
new Color4(255, 128, 128, 255),
new Color4(128, 255, 255, 255),
new Color4(128, 255, 128, 255),
new Color4(255, 187, 255, 255),
new Color4(255, 177, 140, 255),
new Color4(100, 100, 100, 255),
new Color4(142, 199, 255, 255),
};
Assert.AreEqual(expectedColors.Length, comboColors.Count);
for (int i = 0; i < expectedColors.Length; i++)
Assert.AreEqual(expectedColors[i], comboColors[i]);
}
}

[Test]
public void TestGetLastObjectTime()
{
Expand Down
29 changes: 29 additions & 0 deletions osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
using osu.Game.Storyboards;
using osu.Game.Tests.Resources;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Tests.Beatmaps.Formats
{
Expand Down Expand Up @@ -184,6 +185,32 @@ public void TestEncodeMultiSegmentSliderWithFloatingPointError()
Assert.That(decodedSlider.Path.ControlPoints.Count, Is.EqualTo(5));
}

[Test]
public void TestOnlyEightComboColoursEncoded()
{
var beatmapSkin = new LegacyBeatmapSkin(new BeatmapInfo(), null)
{
Configuration =
{
CustomComboColours =
{
new Color4(1, 1, 1, 255),
new Color4(2, 2, 2, 255),
new Color4(3, 3, 3, 255),
new Color4(4, 4, 4, 255),
new Color4(5, 5, 5, 255),
new Color4(6, 6, 6, 255),
new Color4(7, 7, 7, 255),
new Color4(8, 8, 8, 255),
new Color4(9, 9, 9, 255),
}
}
};

var decodedAfterEncode = decodeFromLegacy(encodeToLegacy((new Beatmap(), beatmapSkin)), string.Empty);
Assert.That(decodedAfterEncode.skin.Configuration.CustomComboColours, Has.Count.EqualTo(8));
}

private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b)
{
// equal to null, no need to SequenceEqual
Expand Down Expand Up @@ -212,6 +239,8 @@ private void sort(IBeatmap beatmap)
{
var beatmap = new LegacyBeatmapDecoder { ApplyOffsets = false }.Decode(reader);
var beatmapSkin = new TestLegacySkin(beatmaps_resource_store, name);
stream.Seek(0, SeekOrigin.Begin);
beatmapSkin.Configuration = new LegacySkinDecoder().Decode(reader);
return (convert(beatmap), beatmapSkin);
}
}
Expand Down
73 changes: 73 additions & 0 deletions osu.Game.Tests/Resources/too-many-combo-colours.osu
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
osu file format v14

[General]
AudioFilename: 03. Renatus - Soleily 192kbps.mp3
AudioLeadIn: 0
PreviewTime: 164471
Countdown: 0
SampleSet: Soft
StackLeniency: 0.7
Mode: 0
LetterboxInBreaks: 0
WidescreenStoryboard: 0

[Editor]
Bookmarks: 11505,22054,32604,43153,53703,64252,74802,85351,95901,106450,116999,119637,130186,140735,151285,161834,164471,175020,185570,196119,206669,209306
DistanceSpacing: 1.8
BeatDivisor: 4
GridSize: 4
TimelineZoom: 2

[Metadata]
Title:Renatus
TitleUnicode:Renatus
Artist:Soleily
ArtistUnicode:Soleily
Creator:Gamu
Version:Insane
Source:
Tags:MBC7 Unisphere 地球ヤバイEP Chikyu Yabai
BeatmapID:557821
BeatmapSetID:241526

[Difficulty]
HPDrainRate:6.5
CircleSize:4
OverallDifficulty:8
ApproachRate:9
SliderMultiplier:1.8
SliderTickRate:2

[Events]
//Background and Video events
0,0,"machinetop_background.jpg",0,0
//Break Periods
2,122474,140135
//Storyboard Layer 0 (Background)
//Storyboard Layer 1 (Fail)
//Storyboard Layer 2 (Pass)
//Storyboard Layer 3 (Foreground)
//Storyboard Sound Samples

[TimingPoints]
956,329.67032967033,4,2,0,60,1,0


[Colours]
Combo1:142,199,255
Combo2:255,128,128
Combo3:128,255,255
Combo4:128,255,128
Combo5:255,187,255
Combo6:255,177,140
Combo7:100,100,100
Combo8:142,199,255
Combo9:255,128,128
Combo10:128,255,255
Combo11:128,255,128
Combo12:255,187,255
Combo13:255,177,140
Combo14:100,100,100

[HitObjects]
192,168,956,6,0,P|184:128|200:80,1,90,4|0,1:2|0:0,0:0:0:0:
2 changes: 1 addition & 1 deletion osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ private void handleColours(TextWriter writer)

writer.WriteLine("[Colours]");

for (int i = 0; i < colours.Count; i++)
for (int i = 0; i < Math.Min(colours.Count, LegacyBeatmapDecoder.MAX_COMBO_COLOUR_COUNT); i++)
{
var comboColour = colours[i];

Expand Down
6 changes: 5 additions & 1 deletion osu.Game/Beatmaps/Formats/LegacyDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public abstract class LegacyDecoder<T> : Decoder<T>
{
public const int LATEST_VERSION = 14;

public const int MAX_COMBO_COLOUR_COUNT = 8;

/// <summary>
/// The .osu format (beatmap) version.
///
Expand Down Expand Up @@ -126,7 +128,9 @@ protected void HandleColours<TModel>(TModel output, string line, bool allowAlpha
string[] split = pair.Value.Split(',');
Color4 colour = convertSettingStringToColor4(split, allowAlpha, pair);

bool isCombo = pair.Key.StartsWith(@"Combo", StringComparison.Ordinal);
bool isCombo = pair.Key.StartsWith(@"Combo", StringComparison.Ordinal)
&& int.TryParse(pair.Key[5..], out int comboIndex)
&& comboIndex >= 1 && comboIndex <= MAX_COMBO_COLOUR_COUNT;
Comment on lines +131 to +133
Copy link
Collaborator Author

@bdach bdach Feb 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, I am choosing not to notice that none of this parsing logic actually checks that the combo colours are in order and just parses them sequentially without examining the number in the key, because it's very annoying to handle and it's been the case before I came here. Until someone invariably reports that as an issue, that is.


if (isCombo)
{
Expand Down
22 changes: 18 additions & 4 deletions osu.Game/Graphics/UserInterfaceV2/FormColourPalette.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ public partial class FormColourPalette : CompositeDrawable
public LocalisableString Caption { get; init; }
public LocalisableString HintText { get; init; }

public BindableBool CanAdd { get; } = new BindableBool(true);

private Box background = null!;
private FormFieldCaption caption = null!;
private FillFlowContainer flow = null!;
private RoundedButton addButton = null!;

[Resolved]
private OverlayColourProvider colourProvider { get; set; } = null!;
Expand All @@ -47,8 +50,6 @@ private void load()
Masking = true;
CornerRadius = 5;

RoundedButton button;

InternalChildren = new Drawable[]
{
background = new Box
Expand Down Expand Up @@ -76,7 +77,7 @@ private void load()
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Full,
Spacing = new Vector2(5),
Child = button = new RoundedButton
Child = addButton = new RoundedButton
{
Action = addNewColour,
Size = new Vector2(70),
Expand All @@ -87,7 +88,7 @@ private void load()
},
};

flow.SetLayoutPosition(button, float.MaxValue);
flow.SetLayoutPosition(addButton, float.MaxValue);
}

protected override void LoadComplete()
Expand All @@ -99,6 +100,19 @@ protected override void LoadComplete()
if (args.Action != NotifyCollectionChangedAction.Replace)
updateColours();
}, true);
CanAdd.BindValueChanged(canAdd =>
{
if (canAdd.NewValue)
{
addButton.Enabled.Value = true;
addButton.TooltipText = string.Empty;
}
else
{
addButton.Enabled.Value = false;
addButton.TooltipText = "Maximum combo colours reached";
}
}, true);
updateState();
}

Expand Down
5 changes: 4 additions & 1 deletion osu.Game/Graphics/UserInterfaceV2/RoundedButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Input.Events;
using osu.Framework.Localisation;
using osu.Game.Graphics.Backgrounds;
Expand All @@ -17,7 +18,7 @@

namespace osu.Game.Graphics.UserInterfaceV2
{
public partial class RoundedButton : OsuButton, IFilterable
public partial class RoundedButton : OsuButton, IFilterable, IHasTooltip
{
protected TrianglesV2? Triangles { get; private set; }

Expand Down Expand Up @@ -107,5 +108,7 @@ public bool MatchingFilter
}

public bool FilteringActive { get; set; }

public virtual LocalisableString TooltipText { get; set; }
}
}
5 changes: 2 additions & 3 deletions osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterface;
Expand All @@ -21,7 +20,7 @@

namespace osu.Game.Overlays.BeatmapSet.Buttons
{
public partial class FavouriteButton : HeaderButton, IHasTooltip
public partial class FavouriteButton : HeaderButton
{
public readonly Bindable<APIBeatmapSet> BeatmapSet = new Bindable<APIBeatmapSet>();

Expand All @@ -32,7 +31,7 @@ public partial class FavouriteButton : HeaderButton, IHasTooltip

private readonly IBindable<APIUser> localUser = new Bindable<APIUser>();

public LocalisableString TooltipText
public override LocalisableString TooltipText
{
get
{
Expand Down
5 changes: 1 addition & 4 deletions osu.Game/Overlays/Settings/SettingsButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;

namespace osu.Game.Overlays.Settings
{
public partial class SettingsButton : RoundedButton, IHasTooltip, IConditionalFilterable
public partial class SettingsButton : RoundedButton, IConditionalFilterable
{
public SettingsButton()
{
Expand All @@ -25,8 +24,6 @@ public SettingsButton()
public BindableBool CanBeShown { get; } = new BindableBool(true);
IBindable<bool> IConditionalFilterable.CanBeShown => CanBeShown;

public LocalisableString TooltipText { get; set; }

public override IEnumerable<LocalisableString> FilterTerms
{
get
Expand Down
9 changes: 9 additions & 0 deletions osu.Game/Screens/Edit/Setup/ColoursSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Beatmaps.Formats;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Localisation;
using osu.Game.Skinning;
Expand Down Expand Up @@ -54,6 +55,8 @@ protected override void LoadComplete()
Beatmap.BeatmapSkin.ComboColours.Clear();
Beatmap.BeatmapSkin.ComboColours.AddRange(comboColours.Colours);

updateAddButtonVisibility();

syncingColours = false;
}
});
Expand All @@ -68,8 +71,14 @@ protected override void LoadComplete()
comboColours.Colours.Clear();
comboColours.Colours.AddRange(Beatmap.BeatmapSkin?.ComboColours);

updateAddButtonVisibility();

syncingColours = false;
});

updateAddButtonVisibility();

void updateAddButtonVisibility() => comboColours.CanAdd.Value = comboColours.Colours.Count < LegacyBeatmapDecoder.MAX_COMBO_COLOUR_COUNT;
}
}
}
5 changes: 2 additions & 3 deletions osu.Game/Screens/OnlinePlay/Components/ReadyButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@

using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Online;
using osu.Game.Online.Rooms;

namespace osu.Game.Screens.OnlinePlay.Components
{
public abstract partial class ReadyButton : RoundedButton, IHasTooltip
public abstract partial class ReadyButton : RoundedButton
{
public new readonly BindableBool Enabled = new BindableBool();

Expand All @@ -29,7 +28,7 @@ private void load(OnlinePlayBeatmapAvailabilityTracker beatmapTracker)
private void updateState() =>
base.Enabled.Value = availability.Value.State == DownloadState.LocallyAvailable && Enabled.Value;

public virtual LocalisableString TooltipText
public override LocalisableString TooltipText
{
get
{
Expand Down
Loading
Loading