Skip to content

Commit 41ac049

Browse files
authored
Merge pull request #311 from winnerspiros/copilot/merge-ppy-fork-prioritize-our-fork
Merge 12 upstream ppy/osu commits (ours-priority)
2 parents 1263d53 + 1d584ed commit 41ac049

44 files changed

Lines changed: 690 additions & 113 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

osu.Android.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
</PropertyGroup>
100100

101101
<ItemGroup>
102-
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.507.1" />
102+
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.508.1" />
103103
<!-- `ppy.osu.Framework.NativeLibs` is a transitive dependency of `ppy.osu.Framework`
104104
that ships desktop-only natives (Linux/macOS/Windows) under `runtimes/<rid>/native/`
105105
— including a bare Linux `libbass.so`/`libbass_fx.so`/`libbassmix.so` for linux-arm64.

osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaEditorSaving.cs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,18 @@ public partial class TestSceneManiaEditorSaving : EditorSavingTestScene
2020
[Test]
2121
public void TestKeyCountChange()
2222
{
23-
FormSliderBar<float> keyCount = null!;
23+
FormSliderBar<int> keyCount = null!;
2424

2525
AddStep("go to setup screen", () => InputManager.Key(Key.F4));
26-
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormSliderBar<float>>().First(), () => Is.Not.Null);
26+
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormSliderBar<int>>().First(), () => Is.Not.Null);
2727
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
2828
AddStep("change key count to 8", () =>
2929
{
3030
keyCount.Current.Value = 8;
3131
});
3232
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
3333
AddStep("refuse", () => InputManager.Key(Key.Number2));
34-
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
34+
AddUntilStep("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
3535

3636
AddStep("change key count to 8 again", () =>
3737
{
@@ -41,5 +41,32 @@ public void TestKeyCountChange()
4141
AddStep("acquiesce", () => InputManager.Key(Key.Number1));
4242
AddUntilStep("beatmap became 8K", () => Game.Beatmap.Value.BeatmapInfo.Difficulty.CircleSize, () => Is.EqualTo(8));
4343
}
44+
45+
[Test]
46+
public void TestDualStagesChange()
47+
{
48+
FormCheckBox dualStages = null!;
49+
FormSliderBar<int> keyCount = null!;
50+
51+
AddStep("go to setup screen", () => InputManager.Key(Key.F4));
52+
AddUntilStep("retrieve dual stages checkbox", () => dualStages = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormCheckBox>().First(), () => Is.Not.Null);
53+
AddUntilStep("retrieve key count slider", () => keyCount = Editor.ChildrenOfType<SetupScreen>().Single().ChildrenOfType<FormSliderBar<int>>().First(), () => Is.Not.Null);
54+
AddAssert("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
55+
AddStep("set dual stages", () =>
56+
{
57+
dualStages.Current.Value = true;
58+
});
59+
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().SingleOrDefault()?.CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
60+
AddStep("refuse", () => InputManager.Key(Key.Number2));
61+
AddUntilStep("key count is 5", () => keyCount.Current.Value, () => Is.EqualTo(5));
62+
63+
AddStep("set dual stages again", () =>
64+
{
65+
dualStages.Current.Value = true;
66+
});
67+
AddUntilStep("dialog visible", () => Game.ChildrenOfType<IDialogOverlay>().Single().CurrentDialog, Is.InstanceOf<SaveAndReloadEditorDialog>);
68+
AddStep("acquiesce", () => InputManager.Key(Key.Number1));
69+
AddUntilStep("beatmap became 12K", () => Game.Beatmap.Value.BeatmapInfo.Difficulty.CircleSize, () => Is.EqualTo(12));
70+
}
4471
}
4572
}

osu.Game.Rulesets.Mania.Tests/Editor/TestSceneObjectPlacement.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,28 @@ public void TestNoSeekOnNotePlacement()
5757
AddAssert("time is unchanged", () => EditorClock.CurrentTime, () => Is.EqualTo(initialTime));
5858
}
5959

60+
[Test]
61+
public void TestNoTwoObjectsAtSameTimeAndColumn()
62+
{
63+
AddStep("change seek setting to false", () => config.SetValue(OsuSetting.EditorAutoSeekOnPlacement, false));
64+
AddStep("clear beatmap", () => EditorBeatmap.Clear());
65+
66+
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
67+
AddStep("move mouse to centre of last column", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Last().ScreenSpaceDrawQuad.Centre));
68+
AddStep("place note", () => InputManager.Click(MouseButton.Left));
69+
AddAssert("beatmap has 1 object", () => EditorBeatmap.HitObjects, () => Has.Count.EqualTo(1));
70+
71+
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
72+
AddStep("move mouse to centre of first column", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().First().ScreenSpaceDrawQuad.Centre));
73+
AddStep("place note", () => InputManager.Click(MouseButton.Left));
74+
AddAssert("beatmap has 2 objects", () => EditorBeatmap.HitObjects, () => Has.Count.EqualTo(2));
75+
76+
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));
77+
AddStep("move mouse to centre of last column", () => InputManager.MoveMouseTo(this.ChildrenOfType<Column>().Last().ScreenSpaceDrawQuad.Centre));
78+
AddStep("place note", () => InputManager.Click(MouseButton.Left));
79+
AddAssert("beatmap has 2 objects", () => EditorBeatmap.HitObjects, () => Has.Count.EqualTo(2));
80+
}
81+
6082
private void placeObject()
6183
{
6284
AddStep("select note placement tool", () => InputManager.Key(Key.Number2));

osu.Game.Rulesets.Mania/Edit/Setup/ManiaDifficultySection.cs

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using osu.Framework.Graphics;
88
using osu.Framework.Localisation;
99
using osu.Game.Beatmaps;
10+
using osu.Game.Beatmaps.Formats;
1011
using osu.Game.Graphics.UserInterfaceV2;
1112
using osu.Game.Localisation;
1213
using osu.Game.Resources.Localisation.Web;
@@ -19,13 +20,22 @@ public partial class ManiaDifficultySection : SetupSection
1920
{
2021
public override LocalisableString Title => EditorSetupStrings.DifficultyHeader;
2122

22-
private FormSliderBar<float> keyCountSlider { get; set; } = null!;
23+
private FormSliderBar<int> keyCountSlider { get; set; } = null!;
24+
private FormCheckBox dualStages { get; set; } = null!;
2325
private FormCheckBox specialStyle { get; set; } = null!;
2426
private FormSliderBar<float> healthDrainSlider { get; set; } = null!;
2527
private FormSliderBar<float> overallDifficultySlider { get; set; } = null!;
2628
private FormSliderBar<double> baseVelocitySlider { get; set; } = null!;
2729
private FormSliderBar<double> tickRateSlider { get; set; } = null!;
2830

31+
private readonly BindableInt singleStageKeyCount = new BindableInt
32+
{
33+
Default = (int)BeatmapDifficulty.DEFAULT_DIFFICULTY,
34+
Precision = 1,
35+
};
36+
37+
private readonly BindableInt actualKeyCount = new BindableInt();
38+
2939
[Resolved]
3040
private Editor? editor { get; set; }
3141

@@ -37,20 +47,19 @@ private void load()
3747
{
3848
Children = new Drawable[]
3949
{
40-
keyCountSlider = new FormSliderBar<float>
50+
keyCountSlider = new FormSliderBar<int>
4151
{
4252
Caption = BeatmapsetsStrings.ShowStatsCsMania,
4353
HintText = "The number of columns in the beatmap",
44-
Current = new BindableFloat(Beatmap.Difficulty.CircleSize)
45-
{
46-
Default = BeatmapDifficulty.DEFAULT_DIFFICULTY,
47-
MinValue = 0,
48-
MaxValue = 10,
49-
Precision = 1,
50-
},
54+
Current = singleStageKeyCount,
5155
TransferValueOnCommit = true,
5256
TabbableContentContainer = this,
5357
},
58+
dualStages = new FormCheckBox
59+
{
60+
Caption = "Dual stages",
61+
HintText = "Doubles the number of keys by adding a second stage."
62+
},
5463
specialStyle = new FormCheckBox
5564
{
5665
Caption = "Use special (N+1) style",
@@ -117,16 +126,54 @@ private void load()
117126
},
118127
};
119128

120-
keyCountSlider.Current.BindValueChanged(updateKeyCount);
129+
setStateFromActualKeyCount((int)Beatmap.Difficulty.CircleSize);
130+
131+
keyCountSlider.Current.BindValueChanged(_ => calculateActualKeyCount());
132+
dualStages.Current.BindValueChanged(_ =>
133+
{
134+
updateSingleStageKeyCountBounds();
135+
calculateActualKeyCount();
136+
});
137+
actualKeyCount.BindValueChanged(updateKeyCount);
138+
121139
healthDrainSlider.Current.BindValueChanged(_ => updateValues());
122140
overallDifficultySlider.Current.BindValueChanged(_ => updateValues());
123141
baseVelocitySlider.Current.BindValueChanged(_ => updateValues());
124142
tickRateSlider.Current.BindValueChanged(_ => updateValues());
125143
}
126144

145+
private void updateSingleStageKeyCountBounds()
146+
{
147+
singleStageKeyCount.MinValue = dualStages.Current.Value ? ManiaRuleset.MAX_STAGE_KEYS / 2 + 1 : 1;
148+
singleStageKeyCount.MaxValue = dualStages.Current.Value ? LegacyBeatmapDecoder.MAX_MANIA_KEY_COUNT / 2 : ManiaRuleset.MAX_STAGE_KEYS;
149+
}
150+
151+
private void setStateFromActualKeyCount(int keyCount)
152+
{
153+
actualKeyCount.Value = keyCount;
154+
155+
if (keyCount > 10)
156+
{
157+
dualStages.Current.Value = true;
158+
singleStageKeyCount.Value = keyCount / 2;
159+
}
160+
else
161+
{
162+
dualStages.Current.Value = false;
163+
singleStageKeyCount.Value = keyCount;
164+
}
165+
166+
updateSingleStageKeyCountBounds();
167+
}
168+
169+
private void calculateActualKeyCount()
170+
{
171+
actualKeyCount.Value = keyCountSlider.Current.Value * (dualStages.Current.Value ? 2 : 1);
172+
}
173+
127174
private bool updatingKeyCount;
128175

129-
private void updateKeyCount(ValueChangedEvent<float> keyCount)
176+
private void updateKeyCount(ValueChangedEvent<int> keyCount)
130177
{
131178
if (updatingKeyCount) return;
132179

@@ -143,7 +190,8 @@ private void updateKeyCount(ValueChangedEvent<float> keyCount)
143190
Schedule(() =>
144191
{
145192
changeHandler!.RestoreState(-1);
146-
Beatmap.Difficulty.CircleSize = keyCountSlider.Current.Value = keyCount.OldValue;
193+
Beatmap.Difficulty.CircleSize = keyCount.OldValue;
194+
setStateFromActualKeyCount(keyCount.OldValue);
147195
updatingKeyCount = false;
148196
});
149197
}
@@ -158,7 +206,7 @@ private void updateValues()
158206
{
159207
// for now, update these on commit rather than making BeatmapMetadata bindables.
160208
// after switching database engines we can reconsider if switching to bindables is a good direction.
161-
Beatmap.Difficulty.CircleSize = keyCountSlider.Current.Value;
209+
Beatmap.Difficulty.CircleSize = actualKeyCount.Value;
162210
Beatmap.SpecialStyle = specialStyle.Current.Value;
163211
Beatmap.Difficulty.DrainRate = healthDrainSlider.Current.Value;
164212
Beatmap.Difficulty.OverallDifficulty = overallDifficultySlider.Current.Value;

osu.Game.Rulesets.Mania/ManiaRuleset.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,22 @@ public override IEnumerable<RulesetBeatmapAttribute> GetBeatmapAttributesForDisp
485485
};
486486
}
487487

488+
public override IEnumerable<RulesetBeatmapAttribute> GetBeatmapAttributesForRankedPlayCard(IBeatmapInfo beatmapInfo, IReadOnlyCollection<Mod> mods)
489+
{
490+
var attributes = GetBeatmapAttributesForDisplay(beatmapInfo, mods).ToList();
491+
492+
// Key count attribute isn't relevant to ranked play (it's decided by the pool).
493+
attributes.RemoveAll(a => a.Acronym == "KC");
494+
495+
float holdNoteRatio = beatmapInfo.TotalObjectCount == 0 ? 0 : (float)beatmapInfo.EndTimeObjectCount / beatmapInfo.TotalObjectCount;
496+
attributes.Insert(0, new RulesetBeatmapAttribute("Hold notes", @"HN", holdNoteRatio, holdNoteRatio, 1)
497+
{
498+
ValueFormat = "P0"
499+
});
500+
501+
return attributes;
502+
}
503+
488504
public override IRulesetFilterCriteria CreateRulesetFilterCriteria()
489505
{
490506
return new ManiaFilterCriteria();

osu.Game.Rulesets.Osu.Tests/Editor/TestSceneObjectObjectSnap.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ public void TestHitCircleSnapsToSliderEnd()
7373

7474
AddStep("end slider placement", () => InputManager.Click(MouseButton.Right));
7575

76+
AddStep("seek to slider end", () =>
77+
{
78+
var slider = (Slider)EditorBeatmap.HitObjects.Single();
79+
EditorClock.Seek(slider.EndTime);
80+
});
81+
7682
AddStep("enter circle placement mode", () => InputManager.Key(Key.Number2));
7783

7884
AddStep("move mouse slightly", () => InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre + new Vector2(playfield.ScreenSpaceDrawQuad.Width * 0.205f, 0)));

osu.Game.Tests/Extensions/NumberFormattingExtensionsTest.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,15 @@ public string TestDouble(double input, bool percent, int decimalDigits)
5151
[TestCase(0.4, true, 2, ExpectedResult = "40%")]
5252
[TestCase(1e-6, false, 6, ExpectedResult = "0,000001")]
5353
[TestCase(0.48333, true, 4, ExpectedResult = "48,33%")]
54-
public string TestCultureSensitivity(double input, bool percent, int decimalDigits)
54+
public string TestCultureSensitivityDecimalPoint(double input, bool percent, int decimalDigits)
55+
{
56+
return input.ToStandardFormattedString(decimalDigits, percent);
57+
}
58+
59+
[Test]
60+
[SetCulture("sv-SE")]
61+
[TestCase(-1e-6, false, 6, ExpectedResult = "−0,000001")]
62+
public string TestCultureSensitivityNegativeSign(double input, bool percent, int decimalDigits)
5563
{
5664
return input.ToStandardFormattedString(decimalDigits, percent);
5765
}

0 commit comments

Comments
 (0)